Closed kpagan closed 1 year ago
I can't debug screenshots I'm afraid. While it's clear that your game is taking a while to destroy this Scene, it's not a global change that impacts every game in 3.60, so it's going to need a lot more debugging to narrow down - ideally the game itself, so a test case can be created.
Thank you for your prompt reply!
The game itself is hosted on GitHub and you can view the source code on the https://github.com/kpagan/Phaser3Airfighter/tree/phaser3.60 branch.
I don't know if I am doing something extraordinary but if you like to take a look then check src\scenes\ui\LevelCompleteModal.ts
where you click the OK button to go to the main menu scene. The scenes that are shut down are the src\scenes\CloudScene.ts
and the src\scenes\UiScene.ts
.
Thanks
Hello! I managed to narrow down the bottleneck!
I use particle emitters on the enemy sprites. These sprites are pooled in a GameObjects group. When the sprite was hit I would deactivate it and return it to the group. But when the sprite was spawned again pulling it from the group then I was re-creating the particle emitter. With the change in the API of Phaser 3.60.0 to the particle emitters it seems that the old one was still around and when the scene was shutting down then all the emitters were destroyed during that time. Now I check if the particle emitter is already instantiated so I will not create it again and the shutdown takes a lot less time, under 1 second.
However, it still takes about twice the time compared to 3.55.2 which would take under 500ms.
Using again the Chrome profiler I saw that it takes some milliseconds (around 20) in the Particle.destroy()
method and especially in the this.anims.destroy();
line. However, I don't use animation in my emitters. This time adds up and takes some considerable amount of time to cleanup.
Maybe this can be improved.
Looks like removeListener()
is the culprit.
Yeah, we can skip installing the AnimationState
unless the particle config has an anims
property - that should help a lot.
Thank you very much. I am glad that my info helped. Let me know if I can help further! Currently this is not a blocking issue for me anymore. However, I am looking forward for a fix!
@kpagan I made a quick test and found destroying 10k particles took 500ms — but that's quite a lot of particles. So you might also check to see that you're not creating more particles than you intend to somehow.
Thanks @samme! I don't think I use that many particles. The configuration for the emitter is the following and I have about 7 instances of them:
const particles = this.scene.add.particles(undefined, undefined, texture, {
...(config.frame && { frame: config.frame }),
quantity: 100,
lifespan: { min: 0, max: 70 },
accelerationX: -500,
speedX: -1000,
alpha: { start: 0.5, end: 0, ease: 'Sine.easeIn' },
scale: { start: 0.7, end: 0 },
blendMode: 'SCREEN',
follow: f,
followOffset: { x: -10 + (config.followOffsetX ?? 0), y: -2 + (config.followOffsetY ?? 0) },
moveToX: {
onEmit: () => {
return f.x + (config.moveToXOffset ?? 0);
},
onUpdate: () => {
return f.x + (config.moveToXOffset ?? 0);
}
},
moveToY: {
onEmit: () => {
return f.y + (config.moveToYOffset ?? 0) + Phaser.Math.Between(-3, 3);
},
onUpdate: () => {
return f.y + (config.moveToYOffset ?? 0) + Phaser.Math.Between(-3, 3);
}
},
});
Thanks @samme! I don't think I use that many particles. The configuration for the emitter is the following and I have about 7 instances of them:
const particles = this.scene.add.particles(undefined, undefined, texture, { ...(config.frame && { frame: config.frame }), quantity: 100, lifespan: { min: 0, max: 70 }, accelerationX: -500, speedX: -1000, alpha: { start: 0.5, end: 0, ease: 'Sine.easeIn' }, scale: { start: 0.7, end: 0 }, blendMode: 'SCREEN', follow: f, followOffset: { x: -10 + (config.followOffsetX ?? 0), y: -2 + (config.followOffsetY ?? 0) }, moveToX: { onEmit: () => { return f.x + (config.moveToXOffset ?? 0); }, onUpdate: () => { return f.x + (config.moveToXOffset ?? 0); } }, moveToY: { onEmit: () => { return f.y + (config.moveToYOffset ?? 0) + Phaser.Math.Between(-3, 3); }, onUpdate: () => { return f.y + (config.moveToYOffset ?? 0) + Phaser.Math.Between(-3, 3); } }, });
Maybe this is the problem?
That could be 7 * 1000 = 7000 particles at least.
Wow thanks @ddanushkin ! I had this code taken from the labs examples and never thought what this reserve
function does. Removing it altogether saved me about 500ms.
@samme please note that this reserve is not in the particle emitter that would have 7 instances but still this FireSmokeComponent class has 3 particle emitters each one reserving 1000 particles and I had it created 2 times so in total 2 3 1000 = 6000 particles that were actually useless because they would not add a visual effect.
It makes me wonder how it worked in Phaser 3.55.2 though. I guess the particle emitters were never destroyed but they would remain in memory and never garbage collected thus causing a memory leak. Good thing that this is fixed now.
Thank you all guys for all the help!!!
reserve()
always creates new particles.
You can check these with
console.log('particles', this.fire.getParticleCount());
Since not much have been posted on this issue and I have resolved the problem this issue can be closed. Thank you all for your precious help!
Version
Description
Hello, I was developing a space shooter game with Phaser 3.55.2 and after the 3.60.0 release I started migrating to the new version. After the code migration I tested the game and found out that when I complete a level and click the OK button to return to the main menu scene it takes almost 10 seconds to transition to the scene. I run a performance analysis with the Chrome profile and it seems that the removeListener, destroy and preDestroy methods to take too long. In 3.55.2 this would take just milliseconds. You can check the screenshot of the Chrome profiler. When the scenes are shutting down I remove all listeners. However, I tried to comment out the code that cleans up but it still takes around 10 seconds.
Example Test Code
Additional Information