CrabBoy Posted October 30, 2018 Share Posted October 30, 2018 Hi! character in my game is this cat: 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! Link to comment Share on other sites More sharing options...
samme Posted October 31, 2018 Share Posted October 31, 2018 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. Link to comment Share on other sites More sharing options...
CrabBoy Posted October 31, 2018 Author Share Posted October 31, 2018 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! Link to comment Share on other sites More sharing options...
webdva Posted November 26, 2018 Share Posted November 26, 2018 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? Link to comment Share on other sites More sharing options...
samme Posted November 27, 2018 Share Posted November 27, 2018 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. dude78 and webdva 1 1 Link to comment Share on other sites More sharing options...
webdva Posted November 30, 2018 Share Posted November 30, 2018 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. Link to comment Share on other sites More sharing options...
Recommended Posts