2
\$\begingroup\$

I'm writing a tank trouble clone just for fun using phaser and node, so this is my tank instantiation

tank = game.add.sprite(Math.random() * 800, Math.random() * 640, 'tank');       
tank.anchor.setTo(0.5, 0.5);
tank.scale.setTo(0.5, 0.5);
game.physics.arcade.enable(tank);   
tank.body.immovable = true;
tank.body.collideWorldBounds = true;

This is how an enemy tank is defined at the client

var Enemy = function (game, id, x, y, angle) {  
    this.id = id;
    this.x = x;
    this.y = y;
    this.angle = angle;
    // set the tank properties
    this.tankEnemy = game.add.sprite(this.x, this.y, 'enemy');
    this.tankEnemy.anchor.setTo(0.5, 0.5);
    this.tankEnemy.scale.setTo(0.5, 0.5);
    // game.physics.arcade.enable(this.tankEnemy)   
    // this.tankEnemy.body.immovable = true;
    // this.tankEnemy.body.collideWorldBounds = true;   
}

The problem is in the above case I have enemy tank at the client as a non body (which means I'm checking the collision between a "body" and a "non body") and when I try to check collision

game.physics.arcade.collide(tank, enemies[i].tankEnemy);

It doesn't work.

So I tried making it a body by un-commenting the code, now the enemy tank behaves more weirdly than before. Whenever a client moves, it gains velocity for other clients, making it go beyond the map and becoming invisible. Whereas I'm just changing the coordinates for other clients -

function tankUpdate (data) {
    // when the update event is fired
    var moveTank = findTank(data.id);
    if (!moveTank) {
        console.log('tank not found');
        return;
    }
    // update the tank location
    moveTank.tankEnemy.x = data.x;
    moveTank.tankEnemy.y = data.y;
    moveTank.tankEnemy.angle = data.angle;
}

This is how a client emits update event -

socket.emit('update location', {x: tank.x, y: tank.y, angle: tank.angle});

The server in turn broadcasts this update, which leads to the calling of tankUpdate.

What is the right way to implement this? I just want to prevent the collision between tanks.

EDIT

After a long discussion with @Hexus on slack we concluded with these points which solved the issue -

  1. I was not sending the velocity to the server. (@Hexus mentioned it in his answer).

  2. I was setting the sprite.x property which was conflicting with the position of body. sprite.body.x is the right property to set.

  3. I was updating the position and velocity as soon as I received from the server which leads to a shaky and not-so-smooth movement. The idea is to create a buffer and then update.

  4. Lastly but the most important, if you are testing the game without two instances running on the same machine/browser make sure you set game.stage.disableVisibilityChange = true; in your create method.

Again thanks a lot to @Hexus for helping!

\$\endgroup\$
1
\$\begingroup\$

Make sure you're sending the velocity of your physics bodies from the server too. Position alone won't cut it, because it's not the only thing that impacts how the game objects move.

The most secure way to do this, to help prevent cheating, is to only send input from the client to the server. You can then simulate physics server side for an authoritative game state.

You can of course still simulate physics on the client, but do so while updating the state as sent from the server.

Ultimately, make sure your server sends across any state that affects the movement of your physics bodies. If you interpolate all of these properties over time, you should hopefully achieve some smooth results.

I know that running Arcade Physics with Node.js is pretty difficult because it's so tightly coupled to the rest of the framework, so in your case it will probably be easiest to trust the client's state, at least to see it working.

Edit:

For physics-enabled Phaser sprites, make sure you're setting sprite.body.position.x and y, not the sprite position, because the body will always override this.

Edit 2:

Having looked over your code, I noticed you're updating physics bodies as soon as you receive the data. This doesn't play well with Phaser, as it expects certain changes to happen at certain times.

If you buffer your updates in an array, then loop through and apply them in your update() method, you should be good to go.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks for answering! I tried to send everything being changed for the client to the server but sadly, it's still suffering from the same bug. I'll create a gif and share. \$\endgroup\$ – hashcode55 May 29 '17 at 19:48
  • \$\begingroup\$ Wow, something weird happened. I thought of just sending the velocity. Upon logging, the velocity is BEING set but the tank doesn't move. Any guess? \$\endgroup\$ – hashcode55 May 29 '17 at 19:54
  • \$\begingroup\$ Are you sure you're setting it on the body in the update method? Doesn't sound right, it should be like setting velocity any other way. \$\endgroup\$ – Hexus May 29 '17 at 20:08
  • \$\begingroup\$ Yeah, I'm setting it when the server emits an "update" event. \$\endgroup\$ – hashcode55 May 29 '17 at 20:18
  • \$\begingroup\$ Anyways checkout this gif - media.giphy.com/media/xUA7aRSKi2zQUQr744/giphy.gif \$\endgroup\$ – hashcode55 May 29 '17 at 20:19

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.