javascript item splice self out of list - javascript

If I have an array of objects is there any way possible for the item to splice itself out of the array that contains it?
For example: If a bad guy dies he will splice himself out of the array of active enemies.
I probably sound crazy but that ability would simplify my code dramatically, so I hope for something cool =)

The way you would do it is as follows:
var game_state = { active_enemies: [] };
function Enemy() {
// Various enemy-specific things go here
}
Enemy.prototype.remove = function() {
// NOTE: indexOf is not supported in all browsers (IE < 8 most importantly)
// You will probably either want to use a shim like es5-shim.js
// or a utility belt like Underscore.js
var i = game_state.active_enemies.indexOf(this);
game_state.active_enemies.splice(i, 1);
}
See:
Es5-Shim
Underscore.js
Notta bene: There are a couple of issues here with this manner of handling game state. Make sure you are consistent (i.e. don't have enemies remove themselves from the list of active enemies, but heroes remove enemies from the map). It will also make things more difficult to comprehend as the code gets more complex (your Enemy not only is an in-game enemy, but also a map state manager, but it's probably not the only map state manager. When you want to make changes to how you manage map state, you want to make sure that code is structured in such a way that you only need to change it in one place [preferably]).

Assuming the bad guy knows what list he's in, why not?
BadGuy.prototype.die = function()
{
activeEnemies.splice(activeEnemies.indexOf(this), 1);
}
By the way, for older browsers to use indexOf on Arrays, you'll need to add it manually.

You kind of want to avoid circular references

I would suggest creating an object/class that represents the active enemies list. Create methods on that instance for adding/removing a given item from the list - abstracting the inner workings of the data structure from the outside world. If the active enemies list is global (e.g. there's only one of them), then you can just reference it directly to call the remove function when you die. If it's not global, then you'll have to give each item a reference to the list so it can call the function to remove itself.

You can also use an object and instead of splice, delete the enemy:
var activeEnemies = {};
function Enemy() {
this.id = Enemy.getId(); // function to return unique id
activeEnemies[this.id] = this;
// ....
}
Enemy.getId = (function() {
var count = 0;
return function() {
return 'enemyNumber' + count++;
}
}());
Enemy.prototype.exterminate = function() {
// do tidy up
delete activeEnemies[this.id];
}
Enemy.prototype.showId = function() {
console.log(this.id);
}
Enemy.prototype.showEnemies = function() {
var enemyList = [];
for (var enemy in activeEnemies) {
if (activeEnemies.hasOwnProperty(enemy)) {
enemyList.push(enemy);
}
}
return enemyList.join('\n');
}
var e0 = new Enemy();
var e1 = new Enemy();
console.log( Enemy.prototype.showEnemies() ); // enemyNumber0
// enemyNumber1
e0.exterminate();
console.log( Enemy.prototype.showEnemies() ); // enemyNumber1

Related

Javascript prototype function override when x

In my case, I'm using the Phaser framework.
So in this example I'm extending the Group class of phaser. Every 'actor' class (Sprite, Group, ...) calls upon the update() prototype every few miliseconds.
My idea was to extend this function only when the application runs on a desktop (so not on a phone).
for example:
var MousePointer = function (game, parent, name) {
Phaser.Group.call(this, game, parent, name);
this.init();
};
MousePointer.prototype = Object.create(Phaser.Group.prototype);
MousePointer.prototype.constructor = MousePointer;
MousePointer.prototype.init = function () {
// ... init
};
MousePointer.prototype.update = function () {
// Do something when on desktop
};
I can't possibly use an if clausule in the update() function to check whether the player is on dekstop/tablet/phone. So is there a way to actually override the prototype on initialisation?
for example (pseudocode):
if(onPhone)
MousePointer.prototype.update = parent.prototype.update;
else
MousePointer.prototype.update = this.update;
Well, you've kind of already written the answer for yourself, haven't you? This code (not inside the init method).
if(onPhone) {
MousePointer.prototype.update = function(){//Phone implementation};
} else {
MousePointer.prototype.update = function(){//Other implementation};
}
I advise against starting off with the "regular" function and then potentially overriding it, since you're just declaring it for nothing.
I think a better way to do this would be to write two different classes that shares the same parent, and then write different update() implementations for them. Then you can just do something like:
if(phone) {
var obj = new PhoneMousePointerObject();
} else {
var obj = new DesktopMousePointerObject();
}
// ... later
obj.update()

How do I sort the existing stream in rxjs?

I'm new to RxJs. I have a response stream which is getting data from ajax. Also, I have another button to sort by. I can sort without any problem. My question is if I do the sorting and updating properly? What I'm doing is essentially just empty the child nodes and append new result.
(function($, _) {
var fetchRepoButton = $('.fetch');
var sortByButton = $('.sort-by');
var fetchRepoClickStream = Rx.Observable.fromEvent(fetchRepoButton, 'click');
var sortByClickStream = Rx.Observable.fromEvent(sortByButton, 'click');
var requestStream = fetchRepoClickStream.map(function() {
return '/api';
});
var responseStream = requestStream.flatMap(function (requestUrl) {
return Rx.Observable.fromPromise($.getJSON(requestUrl));
});
responseStream.subscribe(function (es) {
var repositories = $('.container');
repositories.empty();
var names = es.map(function (e) {
return {name: e.name};
}).forEach(function (e) {
var rep = $('<div>');
rep.html(e.name);
repositories.append(rep);
});
});
var sortByStream = sortByClickStream.combineLatest(responseStream, function (click, es) {
return _.sortBy(es, function(e) {
return e.count;
}).reverse().map(function (e) {
return {name: e.name, count: e.count};
});
});
sortByStream.subscribe(function(es) {
var repositories = $('.container');
repositories.empty();
var names = es.map(function (e) {
return {name: e.name};
}).forEach(function (e) {
var rep = $('<div>');
rep.html(e.name);
repositories.append(e);
});
});
})($, _);
I'm playing with the code right now. So there might be duplication.
There is nothing incorrect with your code, and your RxJS usage looks fine, though your DOM usage is not as optimized as it could be. Creating/deleting all those DOM elements is a relatively expensive process, so ideally you want to resume elements where possible. Your sorting code seems ripe for optimizing in this respect.
When you sort your list, you know that DOM elements already exist for each. Instead of deleting all of them, then recreating them in the right order, I would instead use detach() to remove the element from the page and return it, then later use container.append(element) to add them in the right order.
If I was implementing it, I'd do something like rep.data('listCount', e.count) when I originally create the element, so we can sort the jQuery elements directly, then sort the list with:
sortByClickStream.subscribe(function() {
var container = $('.container');
// `.children()` returns raw DOM elements, so wrap each in jQuery
_.map(container.children(), function(el) { return $(el); })
.sortBy(function(item) { return item.data('listCount'); })
.reverse()
.forEach(function(item) {
item.detach();
container.append(item);
});
});
Doing something similar with the response stream list is possible, but a lot more work, since you can't guarantee that each element in the latest list already has an element.
Overall, what you have will work fine, and should be fast enough for small/medium-sized lists. If it appears to get sluggish with your expected list size, then I'd start optimizing DOM code. Frameworks like Angular have entire libraries dedicated to 'DOM diffing' to figure out the minimal number of changes needed to modify the DOM for updated content. If you are doing a lot of this sort of content updates, I'd look into using a library/framework that has this built-in.

javascript method is undefined

I'm trying to learn javascript. As part of that effort, I am writing a basic minimax AI. I have the following methods:
Computer.prototype.expand = function(node) {
/* adds all state action pairs to the node.successors array */
};
Computer.prototype.getMove = function(boardAr) {
console.log("getMove");
var b2 = boardAr.slice();
var i;
var action;
this.root = new TNode(b2, this.mark);
this.root.AIPlayedLast = false;
this.expand(this.root);
this.root.successors.forEach(this.minVal);
action = maxNode(root.successors);
this.draw(action);
registerMove(action, this.mark);
};
Computer.prototype.minVal = function(node) {
if (node.isTerminal) {
return;
} else {
this.expand(node);
node.successors.forEach(maxVal);
node.utility = this.minNode(node.successors).utility;
}
};
When the getMove method is called the subsequent call to expand goes as expected. But, when expand is called from the minVal method I get: Uncaught TypeError: undefined is not a function. I'm utterly perplexed by this. Any help/suggestions would be greatly appreciated.
I think the reason is in this row:
this.root.successors.forEach(this.minVal);
You pass minVal as contextless reference, it will not be called in a context of your Computer instance (this)
Here is how you can improve it:
var self = this;
this.root.successors.forEach(function() {
self.minVal.apply(self,arguments);
})
The simplest and quickest solution is just to change
this.root.successors.forEach(this.minVal);
to
this.root.successors.forEach(this.minVal.bind(this))
This solves the problem in the same as the other answers, but in a way some might consider more compact.
Or, you can pass a "this" to the forEach function as the second argument, a somewhat under-utilized feature of forEach:
this.root.successors.forEach(this.minVal, this)
This feature is also available on other Array prototype methods that take functions, including map, filter, some, every (but not reduce and reduceRight).
ES6 arrow functions handle this differently, so you can do
this.root.successors(forEach(e => this.minVal(e)));
The forEach() method might be called for each of the successors. So, you pass the Computer::minVal method (this.minVal), but with the TNode(?) as this-pointer. Try:
var that = this;
this.root.successors.forEach(function(node) {
that.minVal(node));
});

Create array of objects Javascript

I created this Object with 3 properties:
Node = {
name : "",
isOkay : true,
rotation : 0.0
};
How would i go creating an array of these objects, in size of 100.
So later i could do something like this:
nodeList[74].name = "Peter";
nodeList[74].isOkay = false;
nodeList[74].rotation = 1.3;
or similar...
I'm really new to this, i found couple of topics about this, but it never compiles properly.
I would be really grateful if anyone could show the proper syntax, Thanks!
I would use this way:
var Node = function() {
this.name = "";
this.isOkay = true;
this.rotation = 0.0
}
var nodeList = [];
for (var i = 0; i < 10; i++)
{
nodeList.push(new Node());
}
nodeList[0].name = "test";
So you could create a new object(really new) in order to manage it later. Look here.
EDIT:
What I have done is created an object with a constructor method, you can check it on MDN here.
Creating an object like you have done:
var Node = { /* ... */ }
Is like having one object initiated. To have another, you'll have to write another one and so on. With that contructor you may create any instances you want based on that model.
You might want to do this lazily
Depending on the situation might be helpful to do this lazily
var Node = function(name, isOkay,rotation){
if(!(this instanceof Node)) return new Node(name,isOkay,rotation);
else {
this.name = name;
this.isOkay = isOkay;
this.rotation = rotation;
}
}
var NodeCollective = function(numberOfNodes){
if(!(this instanceof NodeCollective)) return new NodeCollective(numberOfNodes);
else{
var _collective={};
var _defaultName = "", _defaultIsOkay = true, _defaultRotation=0.0;
this.length = numberOfNodes;
this.getNode=function(nodeNumber){
if(!_collective.hasOwnProperty(nodeNumber) && nodeNumber < numberOfNodes){
_collective[nodeNumber]=
Node(_defaultName,_defaultIsOkay,_defaultRotation);
}
//I am just assuming I am not going to get garbage
//you can put in checks to make sure everything is kosher
//if you really want to
return _collective[nodeNumber];
};
}
}
but it also depends on what you are trying to do... if you might not be getting all of the nodes in your program then implementing them in some way that avoids greedily creating them could save you a lot of time if the code is executed often, but if the piece of code isn't executed often this might be over kill.
var nodeList = []; // create empty array
nodeList.push(Node); // add the object to the end of the array
nodeList[0].rotation = 1.3; // set rotation property of the object
console.log(nodeList[0]); // prints the object to console

Game Server OOP Design

I have a class called Room, with an array containing all the Player entities as one of its properties,
players = [];
In the Room class is a method that only returns the players who actually competed in the round.
// below method is called by the room's timer
var getPlayersWhoFinished = function() {
playersWhoFinished = [];
for (i = 0; i < players.length; i++) {
if (players[i].isFinished()) {
playersWhoFinished.push(players[i]);
};
};
return playersWhoFinished;
}
So I know that I could just leave the above in the Room class as is, but I already have three other functions with more complex mapping, in an already large class (300+ lines).
I don't understand how to encapsulate these sort of methods into other classes, as they're so closely related to the Room class and all the the Room reference to be sent to the appropiate users.
Modifying the above code and slotting it into Player class would sort of make sense to me, but the only way I can think of getting this to work is using a static method and sending the room object to it.
// players is now a member of the Player class
Player.getPlayersWhoFinished = function(room, players) {
playersWhoFinished = [];
for (i = 0; i < players; i++) {
if (players[i].getRoom() == room) {
playersWhoFinished.push(players[i]);
}
}
return playersWhoFinished;
}
Anyway, this seems cumbersome and inefficent to me. I've really been struggling to figure out how to make my Room class lithe as possible.
Consider splitting logic into Objects and Collections. It is similar to what backbone offers (Model, Collection).
As collections logic is usually specific to objects it contains, but have some shared functionality as well (simple iterations, filters and so on), you can create generic Collection, and then through Inheritance add more methods in order to fit your needs of that specific Object it stores.
So you would have your room:
function Room() {
// ..
this.players = new PlayerCollection();
// ..
}
For collection I've added some 'bonus' methods, so it would look like:
function Collection() {
this.list = [ ];
this.length = 0;
}
// adds item
Collection.prototype.add = function(item) {
this.list.push(item);
this.length = this.list.length;
}
// removes by index
Collection.prototype.remove = function(index) {
this.list.splice(index, 1);
this.length = this.list.length;
}
// finds one item based on filter function, and triggers callback with item and index
Collection.prototype.findOne = function(fn, callback) {
for(var i = 0, len = this.list.length; i < len; ++i) {
var result = fn(this.list[i]);
if (result) {
return callback(this.list[i], i);
}
}
return callback(null, -1);
}
// filters off
Collection.prototype.filter = function(fn) {
return this.list.filter(fn);
}
Then you would define PlayerCollection, that will have extra method just to filter off players who is finished:
function PlayerCollection() {
Collection.call(this);
}
// some inheritance here
PlayerCollection.prototype = Object.create(Collection.prototype);
PlayerCollection.prototype.constructor = PlayerCollection;
// returns list of finished players
PlayerCollection.prototype.finished = function() {
return Collection.prototype.filter.call(this, function(player) {
return player.isFinished();
});
}
You still can reuse that filter method, as it helps to create some bespoke queries.
Your room logic would look like:
var room = new Room();
// add some players to room
// ...
var finishedPlayers = room.players.finished(); // what you need
It looks clear and straight forward, as well keeps all collection logic away from Room, so you can simply reuse it all over your game code. And improving in one place - would improve it as a whole.
Dividing logic into abstracts like that, helps to scale your code and separate dependencies.
Bear in mind Browser support for filter and if you need -IE8, then get shim from here.
The getPlayersWhoFinished() method belongs to Room, which is the object that should track players. You also are performing a search in O(n) complexity every time you need to find finished players, which can be improved.
You could have a callback mean to be called each time a player finishes:
Player.prototype.onFinished = function() {
this.getRoom().addFinished(this);
}
And then manage a private array in Room containing all the finished players:
function Room() {
this._finishedPlayers = [];
}
Room.prototype.addFinished = function(player) {
this._finishedPlayers.push(player);
}
Room.prototype.getPlayersWhoFinished = function() {
return this._finishedPlayers;
}
As a side note, you should always declare variables with var, or else you will get them declared in the global scope (i.e. usually the window object).

Categories

Resources