Game Server OOP Design - javascript

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).

Related

How can I get all completed tasks to clear on function invocation?

I'm working in Angular, and I have checkboxes that switch the Boolean (to signify task completion). I also have two arrays, one that holds a list of objects and another to hold the first key values once completed and cleared.
$scope.taskList = [{
complete: false,
foo: "1",
bar: "2",
baz: "3"
}];
$scope.completedTasks = [];
The below function works properly to clear tasks when only one or two are checked; however, when the number of items checked grows, only a portion of checked items will clear; if you keep invoking the function, eventually all tasks will clear, but I can't figure out how to clear the entire list in one fell swoop.
$scope.clearComplete = function() {
for (var i = 0; i < $scope.taskList.length; i++) {
if ($scope.taskList[i].complete == true) {
$scope.completedTasks.push($scope.taskList[i].foo);
$scope.taskList.splice(i, 1);
}
}
console.log($scope.completedTasks);
return $scope.taskList;
};
I'm at a loss for how to correct the logic and am hoping that some fresh eyes will be able to help me out.
For this project, I'm trying to keep dependencies low, without the help of other helper libraries like Underscore and Lodash.
first of all if you are doing taskList.splic then loop backwards.
otherwise you can do like this:
var incompleteTasks = [];
$scope.tasks.forEach(function(task){
if(task.complete) {
$scope.completedTasks.push(task.foo);
} else {
incompleteTasks.push(task);
}
});
$scope.tasks = incompleteTasks;
so, you will iterating exactly once to your array, and make it happen with very cleaner approach.
You don't need any external libraries to use forEach, or filter. And I would approach it in two steps for readability:
$scope.clearComplete = function() {
//push completed tasks to completedTasks
$scope.taskList.forEach(function(t) {
if(t.complete) {
$scope.completedTasks.push(t.foo);
}
});
//then filter the task list
$scope.taskList = $scope.taskList.filter(function(t) {
return !t.complete;
});
console.log($scope.completedTasks);
return $scope.taskList;
};

State pattern good practice?

I'm currently reading a book on JS design patterns and would like some confirmation about something.
The following code is an illustration of the state pattern as illustrated by the book:
var BankAccountManager = (function () {
function BankAccountManager() {
this.currentState = new GoodStandingState(this);
}
BankAccountManager.prototype.Deposit = function (amount) {
this.currentState.Deposit(amount);
};
BankAccountManager.prototype.Withdraw = function (amount) {
this.currentState.Withdraw(amount);
};
BankAccountManager.prototype.addToBalance = function (amount) {
this.balance += amount;
};
BankAccountManager.prototype.getBalance = function () {
return this.balance;
};
BankAccountManager.prototype.moveToState = function (newState) {
this.currentState = newState;
};
return BankAccountManager;
})();
var GoodStandingState = (function () {
function GoodStandingState(manager) {
this.manager = manager;
}
GoodStandingState.prototype.Deposit = function (amount) {
this.manager.addToBalance(amount);
};
GoodStandingState.prototype.Withdraw = function (amount) {
if (this.manager.getBalance() < amount) {
this.manager.moveToState(new OverdrawnState(this.manager));
}
this.manager.addToBalance(-1 * amount);
};
return GoodStandingState;
})();
In the previous code snippet, BankAccountManager and GoodStandingState keep a reference to each other, creating a cycle.
As I've read, this doesn't pose a problem anymore because of the Mark-and-sweep algorithm that is used for garbage collection:
Periodically, the garbage-collector will start from these roots, find
all objects that are referenced from these roots, then all objects
referenced from these, etc. Starting from the roots, the garbage
collector will thus find all reachable objects and collect all
non-reachable objects.
Still, I wonder if passing this as argument, and binding it as a reference variable to the other object (that is referenced by the current object) is good practice or if it would still be better to avoid it. In another language that applies the reference counting algorithm for GC, I assume that the previous snippet could cause a memory leak.
Is it ok to apply this pattern, or is it still wiser to avoid it?

Handling Complex Dependencies Between Object Properties (Auto Update Dependent Properties)

I have a tree structure of objects, and their properties have very complicated dependencies on surrounding objects determined by where they are in the tree. I have hard coded a lot of these dependencies, and tried to create some sort of update loop (where if a property gets updated, based on the design, all of the properties that depend on it get updated, and in the correct order), but I want to handle it in a more generic/abstract way, instead of hard coding a bunch of update calls to different objects.
Let's say, for example, I have 1 superclass, and 3 subclasses, and then a separate container object.
Shape
properties: parentContainer, index, left, top, width, height
methods: updateLeft(), updateTop(), updateWidth(), updateHeight()
Square inherits from Shape
Triangle inherits from Shape
Circle inherits from Shape
ShapeContainer
properties: shapes
methods: addShape(shape, index), removeShape(index)
I'll give a pseudocode example update method to illustrate how these dependencies crop up:
Square.updateTop() {
var prevShape = null;
if (this.index != 0) {
prevShape = this.parentContainer.shapes[this.index - 1];
}
var nextSquareInContainer = null;
for (var i = this.index; i < this.parentContainer.shapes.length; i++) {
var shape = this.parentContainer.shapes[i];
if(shape instanceof Square) {
nextSquareInContainer = shape;
break;
}
}
var top = 0;
if (prevShape != null && nextSquareInContainer != null) {
top = prevShape.top + nextSquareInContainer.width;
} else {
top = 22;
}
this.top = top;
}
So, any square objects added to the shapeConatiner will depend on the previous shape's top value and the next square found in the container's width value for its top value.
Here is some code to set up an example shape container:
var shapeContainer = new ShapeContainer();
var triangle = new Triangle();
var circle = new Circle();
var square1 = new Square();
var square2 = new Square();
shapeContainer.addShape(triangle, 0);
shapeContainer.addShape(circle, 1);
shapeContainer.addShape(square1, 2);
shapeContainer.addShape(square2, 3);
So, I guess the crux of the issue is, if I update the above circle's top value, I want the top value of square1 to be automatically updated (because there is a one way dependency between square1's top value, and circle's top value). So one way I can do this (the way I've been doing it, in combination with some other specific knowledge of my problem domain to simplify the calls), is to add the code similar to the following to Circle's updateTop method (really it would have to be added to each shape's updateTop method):
Circle.updateTop() {
// Code to actually calculate and update Circle's top value, note this
// may depend on its own set of dependencies
var nextShape = this.parentContainer.shapes[this.index + 1];
if (nextShape instanceof Square) {
nextShape.updateTop();
}
}
This type of design is fine for a few simple dependencies between objects, but my project has dozens of types of objects with probably hundreds of dependencies between their properties. I've coded it this way, but it is very difficult to reason about when trying to add new features, or troubleshoot a bug.
Is there some sort of design pattern out there to set up dependencies between object properties, and then when one property is updated, it updates all of the properties on other objects that depend on it (which may then trigger further updating of properties that depend on the now newly updated properties)? Some sort of declarative syntax for specifying these dependencies would probably be best for readability/maintainability.
Another issue is, a property may have several dependencies, that ALL must be updated before I want that property to update itself.
I've been looking into a pub/sub type of solution, but I thought this was a complicated enough problem to reach out for help. As a side note, I'm working in javascript.
Here is the hackish solution I came up with. I create a wrapper class, that you pass in anonymous functions for getter/setter/updaters. Then you make a call of prop1.dependsOn(prop2) to declaratively set up dependencies. It involves setting up a directed acyclic graph of the dependencies between object properties, and then when a property value is updated, explicitly making a call to resolve the related dependencies using a topological sort. I didn't put much thought into efficiency, and I bet somebody could come up with a much more robust/performant solution, but I think this will do for now. Sorry for the code dump, but I thought it could be of some help to somebody trying to solve a similar problem down the road. If somebody wants to make this syntactically cleaner, be my guest.
// This is a class that will act as a wrapper for all properties
// that we want to tie to our dependency graph.
function Property(initialValue, ctx) {
// Each property will get a unique id.
this.id = (++Property.id).toString();
this.value = initialValue;
this.isUpdated = false;
this.context = ctx;
Property.dependsOn[this.id] = [];
Property.isDependedOnBy[this.id] = [];
Property.idMapping[this.id] = this;
}
// Static properties on Property function.
Property.id = 0;
Property.dependsOn = {};
Property.isDependedOnBy = {};
Property.idMapping = {};
// Calling this updates all dependencies from the node outward.
Property.resolveDependencies = function (node) {
node = node.id;
var visible = [];
// Using Depth First Search to mark visibility (only want to update dependencies that are visible).
var depthFirst = function (node) {
visible.push(node);
for (var i = 0; i < Property.isDependedOnBy[node].length; i++) {
depthFirst(Property.isDependedOnBy[node][i]);
}
};
depthFirst(node);
// Topological sort to make sure updates are done in the correct order.
var generateOrder = function (inbound) {
var noIncomingEdges = [];
for (var key in inbound) {
if (inbound.hasOwnProperty(key)) {
if (inbound[key].length === 0) {
// Only call update if visible.
if (_.indexOf(visible, key) !== -1) {
Property.idMapping[key].computeValue();
}
noIncomingEdges.push(key);
delete inbound[key];
}
}
}
for (var key in inbound) {
if (inbound.hasOwnProperty(key)) {
for (var i = 0; i < noIncomingEdges.length; i++) {
inbound[key] = _.without(inbound[key], noIncomingEdges[i]);
}
}
}
// Check if the object has anymore nodes.
for (var prop in inbound) {
if (Object.prototype.hasOwnProperty.call(inbound, prop)) {
generateOrder(inbound);
}
}
};
generateOrder(_.clone(Property.dependsOn));
};
Property.prototype.get = function () {
return this.value;
}
Property.prototype.set = function (value) {
this.value = value;
}
Property.prototype.computeValue = function () {
// Call code that updates this.value.
};
Property.prototype.dependsOn = function (prop) {
Property.dependsOn[this.id].push(prop.id);
Property.isDependedOnBy[prop.id].push(this.id);
}
function PropertyFactory(methodObject) {
var self = this;
var PropType = function (initialValue) {
Property.call(this, initialValue, self);
}
PropType.prototype = Object.create(Property.prototype);
PropType.prototype.constructor = PropType;
if (methodObject.get !== null) {
PropType.prototype.get = methodObject.get;
}
if (methodObject.set !== null) {
PropType.prototype.set = methodObject.set;
}
if (methodObject.computeValue !== null) {
PropType.prototype.computeValue = methodObject.computeValue;
}
return new PropType(methodObject.initialValue);
}
And here is an example of what setting up a property looks like:
function MyClassContainer() {
this.children = [];
this.prop = PropertyFactory.call(this, {
initialValue: 0,
get: null,
set: null,
computeValue: function () {
var self = this.context;
var updatedVal = self.children[0].prop.get() + self.children[1].prop.get();
this.set(updatedVal);
}
});
}
MyClassContainer.prototype.addChildren = function (child) {
if (this.children.length === 0 || this.children.length === 1) {
// Here is the key line. This line is setting up the dependency between
// object properties.
this.prop.dependsOn(child.prop);
}
this.children.push(child);
}
function MyClass() {
this.prop = PropertyFactory.call(this, {
initialValue: 5,
get: null,
set: null,
computeValue: null
});
}
var c = new MyClassContainer();
var c1 = new MyClass();
var c2 = new MyClass();
c.addChildren(c1);
c.addChildren(c2);
And here is an example of actually updating a property once all of this infrastructure is set up:
c1.prop.set(3);
Property.resolveDependencies(c1.prop);
I feel like this is a pretty powerful pattern for programs that require really complicated dependencies. Knockout JS has something similar, with computedObservables (and they use a wrapper in a similar fashion), but you can only tie the computed property to other properties on the same object from what I can tell. The above pattern allows you to arbitrarily associate object properties as dependencies.

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

javascript item splice self out of list

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

Categories

Resources