6
\$\begingroup\$

I'm currently creating a multiplayer game using the HTML5 framework Phaser.

It's a game where zombies spawn on the map and players have to shoot them to kill them. The zombies target players that are closest to them.

Currently, I'm having my an issue with my design strategy. I'm not sure if this type of game is possible with Phaser due to the movement tracking.

At present, the client is handling all of the player movement, so whenever a player moves, it broadcasts it to the server which sends it to all of the other clients.

However, I would like for the zombies and the bullets to be controlled by the server exclusively. The server then updates each client with the velocity of each zombie and their current position. My reasoning is that anything that isn't player input should be calculated by the server. This will prevent issues such as two clients saying that a zombie died at different times and then trying to communicate with one another, having bullets at different locations at the same time, or zombies spawning at separate times between clients.

Here's an example of a zombie class:

function Zombie(game, data){

this.game = game;

this.id = data.id;
Phaser.Sprite.call(this, this.game, data.x, data.y, 'zombie');
this.anchor.setTo(0.5,0.5);

this.animations.add('right', [0,1,2,3], 7, true);
this.animations.add('left', [4,5,6,7], 7, true);
this.game.physics.arcade.enable(this);
this.body.collideWorldBounds = true;

this.health = data.health;
this.maxHealth = data.maxHealth;
this.speed = data.speed;
this.target = this.game.player;
this.waiting = 100;

this.name = "zombie";
this.healthBary = 20;
this.healthBar = this.game.add.sprite(this.x, this.y + this.healthBary, 'player_health');
this.healthBar.anchor.setTo(0.5, 0.5);
CollisionManager.addObjectToGroup(this, 'baddies');
this.game.add.existing(this);


}
Zombie.prototype = Object.create( Phaser.Sprite.prototype );
Zombie.prototype.constructor = Zombie;
Zombie.prototype.update = function(){

this.updateHealthBar();

                this.moveTowards(this.target);

Zombie.prototype.uTarget = function(target) {
    this.target = target;    
};
Zombie.prototype.moveTowards = function(target){
var x = target.x - this.x;
var y = target.y - this.y;

var mag = Math.sqrt((x * x) + (y * y));

var nx = x / mag;
var ny = y / mag;

this.body.velocity.x = nx * this.speed;
this.body.velocity.y = ny * this.speed;

if(this.body.velocity.x >= 0){
    this.animations.play('right');
}
else if(this.body.velocity.x < 0){
    this.animations.play('left')
}

}
Zombie.prototype.updateHealthBar = function(){
this.healthBar.x = this.x;
this.healthBar.y = this.y + this.healthBary;

var p = (this.health / this.maxHealth);
p = parseFloat(p.toFixed(1));
this.healthBar.frame = 10 - (p * 10);
}
Zombie.prototype._damage = function(amount){
this.health -= amount;
if(this.health <= 0){
    this.kill;
    this.die(true);
}
}

Zombie.prototype.die = function(points){

if(this.game){
    //this.game.baddie_die_sfx.play();
}


WaveManager.onMap--;
CollisionManager.removeObjectFromGroup(this, "baddies");
if(this.healthBar){
    this.healthBar.destroy();
}
socket.emit("kill zombie", {id: this.id});
this.kill();
this.destroy();
}

The problem is that I can't create a Phaser game object on the server (as it's running on a Linux server) because there's no window that can be used. The bullets and zombies need to be Phaser objects for the sake of collision detection, but I can't do that on the server.

I know that I could create a vector of zombies and bullets server-side that would have the information for each bullet/zombie's position at any given time and then update the client, but then I wouldn't be able to use the CollisionManager in Phaser.

Right now, it seems like my only solution is to create my own collision detection system. Are there any alternative ideas?

\$\endgroup\$
  • 1
    \$\begingroup\$ Have you tried something like this? github.com/learnboost/node-canvas \$\endgroup\$ – codename- Mar 31 '14 at 14:36
  • \$\begingroup\$ You shouldn't be using a game engine framework for your server backend to begin with. That's the first problem. \$\endgroup\$ – Vaughan Hilts Mar 31 '14 at 14:57
  • 1
    \$\begingroup\$ Javascript is very flexible, maybe you can fake all that's missing to Phaser quite easily. (using nosuchMethod and/or fake object creation). \$\endgroup\$ – GameAlchemist Mar 31 '14 at 15:07
  • \$\begingroup\$ Have you actually tried it on the server? As long as Phaser doesn't try to call window methods by itself, I can imagine no obstruction to using its collision routines server-side. There's also jsdom, which D3 falls back on when run under node instead of a browser. \$\endgroup\$ – Anko Mar 31 '14 at 15:32
  • \$\begingroup\$ When I attempt to create a "game" on the server side, it gives me an unreferenced object error, which i assume is because a window isn't launched. \$\endgroup\$ – kalittles Mar 31 '14 at 15:44
5
\$\begingroup\$

While in theory it should be possible given that you can construct the Phaser game object with a HEADLESS renderer type, this post from one of the developers seems to suggest that that won't solve your problem, since Phaser still requires the canvas to initialize. That post was in 2013, but I don't see any obvious proof that the issue has been addressed yet (I didn't actually trawl through the source code though).

Your best bet is likely to use something like node-canvas, as per the comments.

However, also as suggested in the comments, I wouldn't recommend using a front-end-oriented game engine like Phaser on your back-end server like this. You should just be able to build a "regular" node.js application that had logical representations of your bullets and zombies, did the simulation on them, and sent them back to clients. JavaScript's dynamic nature should make it easy to interpret or serialize/deserialize the client-side Phaser objects.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.