CrabBoy

[POSSIBLE BUG] Collisions: Sprite.kill() doesn't behave in the expected way

Recommended Posts

Hi!

character in my game is this cat:

phaser-Topic-Photo.png

The cat is class extending group and contains torso and head, both are sprites with arcade physics enable on it. In the game, the cat is pushed up by applying velocity on it and it collects certain items (gameplay is similar to Flip the Gun game, check it out for better understanding).

THE PROBLEM:

In update method, I am constantly checking for collisionse between cat and the items:

this.game.physics.arcade.overlap(this._cat, this._sceneObjectsLayer, this.onObjectCollision, null, this);

My onObjectCollision method looks like this:

onObjectCollision(cat: Phaser.Sprite, item: GeneratedItem) {
  console.log("COLLISION SOURCE IS " + cat.key);
  console.log("COLLISION! OBJECT ID IS " + item.ItemID + "... UPDATE FRAME IS " + this._updateFrameCnt);
  this._items++;
  this._UI.showCount(this._items);
  item.KillItem(); //inside this method I call item.kill()
  this._sceneObjectsLayer.remove(item);
}

Basically, it should just update the total amount of items taken in player UI. The problem is that same item is sometimes collected multiple times. That makes sense - one collision for torso, one for head, but I would expect it not to call this method for the same item after item.kill() is called. I already debugged this and I put the variable this._updateFrameCnt to update method.

Result is this. You can see that the item with certain ID is collected, then it is killed and after few frames it is collected again like no kill() was called on it:

State_game.ts:451 COLLISION SOURCE IS catHead
State_game.ts:452 COLLISION! OBJECT ID IS 0... UPDATE FRAME IS 2034
GeneratedItem.ts:52 KILLING ITEM WITH ID 0 //called from item.KillItem

//and after few frames:
State_game.ts:451 COLLISION SOURCE IS catTorso
State_game.ts:452 COLLISION! OBJECT ID IS 0... UPDATE FRAME IS 2040
GeneratedItem.ts:52 KILLING ITEM WITH ID 0 //called from item.KillItem

Moreover, this sometimes happens for the same sprite (for example it is called twice for head sprite). Is this expected behaviour due the reasons how Phaser handles physics? Seems really strange for me, I would expect to make physics computation after each frame and therefore no second collision should occur, because the item should be dead at the time. Am I missing something here?

Thanks in advance for your responses!

Share this post


Link to post
Share on other sites
15 hours ago, samme said:

Sprites with exists=false are ignored during collision checks, so that would be unexpected unless an item is being revived/reset soon after being killed.

Thanks for your insight! Your comment made me add some log to my Spawn function with Sprite.revive() and it indeed looks like that the item is revived right after it is killed. There is some problem with my item spawning logic, I need to debug more. Thanks!

Share this post


Link to post
Share on other sites

I believe that there is a high probability that this problem is the exact same problem that I recently had for a game I'm making.

On 10/30/2018 at 6:56 AM, CrabBoy said:

I would expect it not to call this method for the same item after item.kill() is called.

That's the same belief I had when I encountered this problem, but as you said :

On 10/30/2018 at 6:56 AM, CrabBoy said:

Is this expected behaviour due the reasons how Phaser handles physics? Seems really strange for me, I would expect to make physics computation after each frame and therefore no second collision should occur, because the item should be dead at the time.

I believe that the reality is that how Phaser handles collisions in its Phaser.Physics.Arcade.overlap function is the cause of this unexpected phenomenon.

What I did to solve this problem was to create an array that would allow you to enqueue the sprites that you wish to have killed and then actually kill those sprites with the use of that array, but only after the current frame as the sprites cannot be properly removed during the current frame due to the way Phaser processes the sprites in the Phaser.Physics.Arcade.overlap function.

this.spritesToBeKilled = [];

At the beginning of Phaser's update function, or at least before each collision checking iteration, the enqueued sprites are killed with the use of iterating over the this.spritesToBeKilled array:

this.spritesToBeKilled.forEach(sprite => {
    this._sceneObjectsLayer.remove(sprite); // Or however you wish to remove the sprites from the game.
});

this.spritesToBeKilled = []; // Resets the array for subsequent collisions.

And during the actual collision checking, inside your collision checking function, the sprites to be killed are added to the this.spritesToBeKilled array instead of being killed inside the collision checking function. But you can still disable the visibility of the colliding sprite during the collision checking:

function onObjectCollision(cat, item) {
    this.spritesToBeKilled.push(item); // Enqueues the sprite for removal from the game during the next frame.
    item.kill(); // The sprite is not actually killed and removed from the game here, but at least it's not visible anymore.
}

P.S. I noticed that I'm replying to a month-old thread. Have you solved your problem?

Share this post


Link to post
Share on other sites
On 11/26/2018 at 11:01 PM, samme said:

kill only deactivates and hides an object. You need destroy if you want to remove it permanently.

Try pendingDestroy if destroying an object from a callback causes problems.

 

Thanks. I didn't know about the Phaser.Sprite.pendingDestroy sprite property. It does seem like a more beneficial solution instead of what I proposed.

I used Phaser.Sprite.kill() so that the sprite would no longer be rendered to the screen as the sprite doesn't get removed inside the Phaser.Physics.Arcade.overlap function during the current frame. Setting the Phaser.Sprite.visible property to false may have been a better decision.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.