I’ve gone over the code for Shape Struggle, and optimized it for performance On my machine, I can’t get it to drop frames in the latest post-compo build, 220.127.116.11. The thing is, my laptop is pretty high-end (2.8GHz Xeon E3-1505M, 64GB RAM), so I’m not sure how well it runs on older machines… I need testers!
I figure my optimization tricks might help other developers, so in brief, here’s how I did it:
- Controller object: I knew even before the compo ended that I needed to set up a controller object to optimize the performance of the up to 500 instances of oEnemy that I’d have active in the game. But the code in the controller object from the 1.0 build was far from optimized. I refactored and streamlined the code, eliminating redundant conditional checks, and pulling code out of loops to make them as tight as possible.
I also pulled some Step event code out of the two most complex objects, oSquare an oPentagon, and put it into the controller object. Doing so enabled me to write some of the code in the controller so that it runs once for all instances of oSquare and oPentagon, rather than once per instance. This makes a huge difference in the amount of calculations necessary when there are hundreds of instances active. No matter how many there are, there’s only one calculation performed.
- Simplified bullet object. At maximum firepower, the player fires 5 bullets per shot, one shot every three steps. At 60fps, that’s 100 bullets per second. That’s 100 creation events per second. I thought I should limit the number of bullets, and also I wanted to limit the range of the player’s weapon, so I put a timer in the bullet object that destroyed the bullet instance after 1 second.
Potentially, I might have optimized this by implementing object pooling, so that rather than creating and destroying bullets, I would re-use the instances so I wouldn’t need to keep creating and destroying them. But first, I tried removing the timer, and found that the game plays and feels exactly the same, so that timer code doesn’t matter. Normally setting a variable and then decrementing it doesn’t take a lot of CPU. But with up to 100 fewer creation events every second, and 100 fewer timers to decrement every step, it adds up.
Object pooling might yield still more performance optimization, but simplifying the objects as much as possible first before making such efforts is smart.
- I also removed the collision check from the bullet object that checks for collisions with the wall, and put it in the wall. There’s only 8 wall instances, so 8 collision checks vs. up to 100 each step means a substantial savings in calculations.