Extreme performance slowdown in my game after a lot of collisions

Hi!

I am trying to identify where a tremendous performance slowdown is in my little game.

I have a global array called bullets, to which I add bullets using this function when a cannon is fired.

function shootBullet(physics, tower, tilesGroup, towers, color) {
    // console.log("shooting bullet for rotation for " + tower.cannon.id);

    sound.play('sfx', markers[4]);
    var bullet = physics.add.sprite(tower.x, tower.y - 50, 'bullet');
    bullet.bounces = 5;

    bullet.onCollide = true;
    var angle = tower.cannon.rotation;
    var speed = 400;
    bullet.targetColor = tower.cannon.targetColor;
    bullet
        // .setVelocity(300, 200)
        .setBounce(1)
        .setScale(0.03)
        .setTint(bullet.targetColor)
        .setCollideWorldBounds(true);


    bullet.anims.create(explosionAnim);
    bullet.body.angularVelocity = angle * 10;
    bullet.body.velocity =  physics.velocityFromRotation(angle, 400, bullet.body.velocity);
    bullet.onCollide = true;
    bullet.body.onWorldBounds = true;
    bullet.firingCompleted = false;
    bullet.UUID = globalBulletCounter;
    bullets.push(bullet);
    globalBulletCounter++;

    bullet.body.world.on('worldbounds', handleBulletBounce, bullet);
    // // physics.add.overlap(bullet, tilesGroup, changeTileColor);
    // physics.add.overlap(bullet, towers, handleTowerHit);
}

This works like a champ, then later in create() I assign collison handling like this (using overlap instead of collide since I want control over the action of the balls)

        this.physics.add.overlap(bullets, tilesGroup, changeTileColor); //works great!
        this.physics.add.overlap(bullets, towers, handleTowerHit);        //also works
        console.log("create completed");

Both callbacks of changeTileColor and handleTowerHit call another method handleBulletBounce, which keeps track of how many bounces a bullet has had. Once they have bouinced 3 times, we play an animation then call destroy() on the bullet.

The Problem

You would think this would work like a champ, but after a few minutes of playing, I can observe that the count of objects in bullets has gone into the hundreds and hundreds. Calling destroy() doesn’t seem to actually delete the objects! I can observe in a perf trace that my JS memory is shooting up to more than a GB for a simple game.

How to prune unused objects without breaking collision?

I tried to add this to update(), filtering out bullets which have active === false, but doing this completely breaks the collision tracking for any objects still on the screen.

//tried this but it breaks collision / overlap, i.e. any remaining objects alive on screen then no longer have tracking

 bullets = bullets.filter(obj => {
    return obj.active === true
  });
        

:wave:

The world bounds event comes from the physics world itself, so you need only one event handler. Remove this line and add to create() instead:

this.physics.world.on('worldbounds', function (body) {
  body.gameObject.handleBulletBounce();
});

(or something similar)

The easiest solution for this is to use a physics group instead. If you destroy a member the group automatically removes it.

var bulletsGroup = this.physics.add.group();

// This will be simpler:
bulletsGroup.defaults = {};

// …

bulletsGroup.add(bullet); // etc.

Ohh adding them as a physics group worked like a charm. Now I see them automatically pruning themselves out of the list (I added a debugView so I could monitor how many items were in there)

I think you’re right that I’m also hindering myself by setting up the bounceWorldBounds listener so many times, I think those excess items linger after the object is destroyed.

Not sure how to fix that though :frowning:

Use just one listener in create(), it should work fine.

this.physics.world.on('worldbounds', function (body) {
  body.gameObject.handleBulletBounce();
});