Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling reset() on Sprite with a P2 body can result in body.data.world == null #917

Closed
jonkelling opened this issue Jun 16, 2014 · 4 comments

Comments

@jonkelling
Copy link
Contributor

Steps:

  1. When a Sprite with a Phaser.Physics.P2.Body has exists set to false--e.g. on kill()--the body is QUEUED to be REMOVED.
  2. The Sprite is now available via getFirstExists(false), for example, and may have reset() called at this time. Calling reset() will set exists = true, which effectively ADDs the body to the world WITHOUT the QUEUE.
  3. The Sprite has health, it exists, is visible, etc. etc., but a split-second later, P2 processes the _toRemove queue and removed the body from the world.
  4. Your Sprite appears dead in the water. Or in space. Or whatever. (humor implied)

Proposed solution: In physics/p2/World.js, the addBody function should remove the body from the _toRemove queue.

@jonkelling
Copy link
Contributor Author

Sorry, that solution didn't work. This one did, though:

Added the following code to the beginning of the Phaser.Physics.P2.Body#addToWorld method:

        if (this.game.physics.p2._toRemove)
            for (var i = 0; i < this.game.physics.p2._toRemove.length; i++)
                if (this.game.physics.p2._toRemove[i] === this)
                    this.game.physics.p2._toRemove.splice(i, 1);

So, it looks like this:

    /**
    * Adds this physics body to the world.
    *
    * @method Phaser.Physics.P2.Body#addToWorld
    */
    addToWorld: function () {

        if (this.game.physics.p2._toRemove)
            for (var i = 0; i < this.game.physics.p2._toRemove.length; i++)
                if (this.game.physics.p2._toRemove[i] === this)
                    this.game.physics.p2._toRemove.splice(i, 1);

        if (this.data.world !== this.game.physics.p2.world)
        {
            this.game.physics.p2.addBody(this);
        }

    },

@jonkelling
Copy link
Contributor Author

I understand I may have submitted this impatiently and that the solution may not be in the best place. It does appear solve the problem, though, and I will try to get back to it when I can. Thanks.

jonkelling added a commit to jonkelling/phaser that referenced this issue Jun 16, 2014
Fix for issue phaserjs#917: Calling reset() on Sprite with a P2 body can result in body.data.world == null.
Calling addToWorld() would previously not check the _toRemove array, which could, if the timing were right, result in a Sprite being revived but then removed from the P2 World--the result of this being the Sprite's data would be in a mixed state causing it to appear visually but not function in the world.
@jonkelling
Copy link
Contributor Author

This code demonstrates the problem. Notice I use setInterval and setTimeout instead of game.time.events.loop. Using the game.....loop functionality, the problem does not occur, but if your trigger is a key press or mouse click, it does. The setInterval/setTimeout operates pretty much to the same effect as using a key press, but you don't have to mash buttons to recreate it. So...notice there are three bullets that fire. After 5 seconds, the first bullet shot disappears and a new one SHOULD fire; however, it just appears and looks stuck, as described in this issue.

var game = new Phaser.Game(800, 600, Phaser.AUTO, 'issue917', { preload: preload, create: create, update: update });

var bulletGroup;
var canFire = true;

function preload()
{
    game.load.image('bullet', 'bullet.png');
}

function create()
{
    game.physics.startSystem(Phaser.Physics.P2JS);

    bulletGroup = game.add.group();
    bulletGroup.enableBody = true;
    bulletGroup.physicsBodyType = Phaser.Physics.P2;
    bulletGroup.createMultiple(3, 'bullet');
    bulletGroup.forEach(function(bullet) {
        game.physics.p2.enable(bullet);
    })

    setInterval(fireNext, 0);
}

function update()
{

}

function fireNext()
{
    if (canFire)
    {
        setTimeout(function() { canFire = true; }, 1000);
        canFire = false;
        var nextBullet = bulletGroup.getFirstExists(false);
        if (nextBullet)
        {
            nextBullet.reset(game.width / 2, game.height - 50);
            nextBullet.body.moveForward(100);
            nextBullet.lifespan = 5000;
        }
    }
}

jonkelling added a commit to jonkelling/phaser that referenced this issue Jun 17, 2014
Fix for issue phaserjs#917: Calling reset() on Sprite with a P2 body can result in body.data.world == null.
Calling addToWorld() would previously not check the _toRemove array, which could, if the timing were right, result in a Sprite being revived but then removed from the P2 World--the result of this being the Sprite's data would be in a mixed state causing it to appear visually but not function in the world.
jonkelling added a commit to jonkelling/phaser that referenced this issue Jun 18, 2014
Fix for issue phaserjs#917: Calling reset() on Sprite with a P2 body can result in body.data.world == null.
Calling addToWorld() would previously not check the _toRemove array, which could, if the timing were right, result in a Sprite being revived but then removed from the P2 World--the result of this being the Sprite's data would be in a mixed state causing it to appear visually but not function in the world.
photonstorm added a commit that referenced this issue Jul 1, 2014
Fix for issue #917, Physics.P2.Body#addToWorld
@photonstorm
Copy link
Collaborator

Merged into dev, thank you :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants