Jump to content

Unexpected behavior with collisions & sprite bodies


Buzugu
 Share

Recommended Posts

Hello everyone !

 

I was doing some experiments with Phaser to understand it and ran into what seemed like a big problem to me which I would like to share.

 

Here's the demo : (removed)

 

Basically the sprite bodies do not seem to follow the sprites accurately at all, and the collisions aren't working well either, with the badnik running straight into the map.

 

I was not sure if these two issues were related or not and since my source code seems simple I decided to put them in the same topic.

 

Here's the source :

(function () {    var game = new Phaser.Game(800, 400, Phaser.CANVAS, '', { preload: preload, create: create, update: update, render: render });    function preload() {        game.load.spritesheet('sonic', 'sonic_running.png', 36, 36, 4);        game.load.spritesheet('badnik', 'badnik.png', 40, 30, 4);        game.load.image('starfield', 'starfield.jpg');        game.load.tilemap('spacelevel', 'tiles-1.png', 'spacelevel.json', null, Phaser.Tilemap.JSON);    }    var keys = Phaser.Keyboard;    var jumpTimer = 0;        var sonic,bg, map;    function create() {        bg = game.add.tileSprite(0, 0, 3000, 500, 'starfield');        map = game.add.tilemap(0, 0, 'spacelevel');        map.setCollisionRange(0, 69, true, true, true, true);        sonic = game.add.sprite(36, 36, 'sonic');        sonic.anchor.setTo(0.5, 0.5);        sonic.body.collideWorldBounds = true;        sonic.body.gravity.y = 100;        sonic.animations.add('run');        sonic.animations.play('run', 30, true);        game.camera.follow(sonic);        badnik = game.add.sprite (400,40, 'badnik');        badnik.body.collideWorldBounds = true;        badnik.body.gravity.y = 100;    }    function update() {        game.physics.collide(sonic, map);        game.physics.collide(badnik, map);        game.physics.collide(sonic, badnik);        if (game.input.keyboard.isDown(keys.SPACEBAR)) {            if (sonic.body.touching.down && game.time.now > jumpTimer) {                sonic.body.velocity.y = -600;                jumpTimer = game.time.now + 500;            }        }        if (game.input.keyboard.isDown(keys.LEFT)) {            sonic.body.velocity.x = 400;        }        sonic.body.velocity.x = 400;    }    function render() {        // game.debug.renderSpriteCorners(sonic);        // game.debug.renderSpriteCollision(sonic, 32, 32);        game.debug.renderSpriteBody(sonic);        game.debug.renderSpriteBody(badnik);    }})();

I am using Phaser 1.0.6a and was able to reproduce the issue on both Firefox and Safari (haven't tried on Chrome), OS X 10.8.

 

Am I doing something wrong ?

 

Thanks a lot for Phaser ! :)

Link to comment
Share on other sites

Yes this is mostly why I re-did the way bodies are handled for the 1.0.7 release. Last night I created a demo game which had a 2000x2000 sized world with a load of tanks roaming around, the camera following you, and collision is working great across it now (camera jitter has gone too). You can play it here actually: http://gametest.mobi/tanks/ and all the code is in the dev branch right now.

Link to comment
Share on other sites

I'll use this threat cause I don't want to spam the forum with topic on my own project :P

 

So what I stumble for several hours was this weird behaviour (which worked cool on older phaser versions):

http://mihail.ilinov.eu/games/PhaserBreakoutJSBodyToSprite/

 

Now I'm using: * v1.0.7 - Built at: Thu, 10 Oct 2013 16:51:46 +0100

 

And here is the problematic code in the update:

 
        if(ball.x < ball.width - wallWidth) {            ball.body.velocity.x = Math.abs(ball.body.velocity.x);        }        if(ball.x > game.world.width - ball.width - wallWidth) {            ball.body.velocity.x *= -ball.body.bounce.x;        }

 

and after "some time" and experiments i came to the conclusion that sprite.x and body.x - differ with 1 to 3px and when there is a check like this the "jitter" appears.

 

So I fixed my problem refactoring the code to:

        if(ball.body.x < ball.body.width - wallWidth) {            ball.body.velocity.x = Math.abs(ball.body.velocity.x);        }        if(ball.body.x > game.world.width - ball.body.width - wallWidth) {            ball.body.velocity.x *= -ball.body.bounce.x;        }

 

I understand that the right thing to check for collision is: body size but since the two sizes were identical... I felt in the trap.

 

And the general question is:

 

Is it normal if body and spite are with the same size, the body to follow behind with 1-3px ?

Link to comment
Share on other sites

BTW that build is really old now :) However... yes it's normal that body.x and sprite.x won't be in sync depending on when you check them. The body will actually be ahead of the sprite, not behind it. The flow goes like this (per game loop)

 

1) Plugins, Input and Tweens are all updated. Any of those could impact a sprite.x value.

2) The World is updated. This will iterate through all sprites and call preUpdate on them.

3) Sprite.preUpdate will sync itself with the worldTransform (as other items in the display list may adjust the sprite position)

4) Sprite.preUpdate then calls Body.preUpdate - this copies the current sprite.x values into the body, and then ...

5) Body calls Physics.updateMotion. This applies velocity, acceleration, etc and will adjust the BODY placement, but not the Sprite.

6) Now the State update is called. By this point the body could be several pixels away from the sprite, so it's important that if you're using velocity/etc that you use body checks in your code.

7) World.postUpdate is run. This calls postUpdate across Sprite and its Body. This basically syncs any Body adjustments back to the main Sprite and updates the Sprites position just in time for ...

8) Render

 

And then it loops. The Body can be adjusted many times during the State update of course (i.e. a physics.collide() could do it lots).

 

I did toy with the idea of putting the body values into the sprite at the end of preUpdate, so they were always accurate when you entered the State update, but it actually made things considerably worse and all you'd need do is adjust the body once (say via collide) and it'd be out of sync right away. Easier to keep everything confined to the body itself, but it probably makes it a bit less obvious from a coding point of view.

Link to comment
Share on other sites

  • 1 month later...

Posting in this thread since it relates to sprite collision issues. When extending `Phaser.Sprite`, I started moving input and animation functionality into my sprite's `update` method, only to find that despite calling `game.physics.collide(sprite, collisionLayer)` in my state's `update` method, certain attributes on the sprite body, such as `body.touching.down`, would never return true.
 
I found the problem to be the fact that in the body's `preUpdate` method, it resets `this.touching.down` and other collision detection booleans to false on the sprite body. Moving my input and animation logic to the beginning of the `preUpdate` method in my sprite got this working properly for me, but I feel like `preUpdate` isn't the appropriate place for that logic?
 
Is there another way that I should be moving my input detection into my sprite object?
Should the collision booleans be reset elsewhere?
Should the sprite's `preUpdate` method be called before the state's `update` method?

Link to comment
Share on other sites

Sprite preUpdate should always be called before the State update, yes. It is part of world.update, which comes before state.update in the game loop, providing the sprite is on the display list somewhere.

 

It is correct that the 'touching' booleans should be reset in the preUpdate, as they are then updated when the body is updated (assuming it actually touched something). In world.postUpdate the new body values are copied to the parent sprite. This happens after state.update is called.

 

It's hard to tell if what you're seeing is a flow error or a limitation of an extended Sprite tbh.

Link to comment
Share on other sites

I had the same issue as @kevinthompson. I resolved it by having each sprite call 'game.physics.collide( this, collsionLayer )' itself rather than doing it in state.update(). in some circumstances this is probably sub-optimal, performance-wise; in my game it happens not to matter. 

 

I think @kevinthompson's last suggestion is the right one. it might not be possible (i.e. it would break something else), but it makes sense to me that every object's preUpdate() method would be called before any object's update(), rather than the current system where World.update() calls its childrens' preUpdate() methods and then their update() methods immediately after.

Link to comment
Share on other sites

It should be fine to split them up like that, but to be honest it probably needs doing as a bigger internal change. For a while now I've not been 100% happy with using the linked list that pixi uses for rendering as the method to sweep world objects, so it feels like it could be modified with that. Sorting out the internal loop + adding in hooks to all the primary sub-systems is my major goal for the 1.2 release (along with proper physics).

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...