link: original post
Instantiate and Destroy. Two incredibly useful functions that can wreak havoc on performance when improperly used together. Let's look at how I devastated the performance of "Tactical Twitch", and what I'm doing to optimize it.
One of my goals for "Tactical Twitch" is to provide an old school, NES era vibe in the game mechanics. To assist in this goal, I want slow bullets. Remember those? The sort of bullets one can see, and jump to dodge if they're quick enough. To make this work, my bullets are GameObjects with their own art work and collision boxes. This allows the player to move around and avoid incoming fire; as appose to a Raycasting solution that would calculate whether or not a bullet hit based on line of site.
Everything from bullets to grenades, rockets, and enemies are their own game objects. These objects are used frequently. In a heated moment there could be a multitude of ammunition in use, and enemies that die and spawn. I wrote the code for this a while ago. When I was last working on this project, I was using a high end desktop. As we approach Summer I've been trying to knock out smaller "to-do" tasks in preparation of resuming development. I'm currently working on my laptop which has a mid range i5, and Intel Graphics. My frame-rate is in the upper 20s. It's playable, but not really enjoyable. I've started to fix this, but first I had to identify the performance issues. Spoiler alert, it's largely my abuse of Instantiate and Destroy.
I'll quickly walk through the posts that helped me realize my problem.
These two threads helped me identify the logic I should have been using when working with these functions. It's actually a pretty simple idea. Reuse what already exists, instead of instantiating and destroying on the fly. I think it's easy enough to say and understand, but what does it look like in practice?
In my game, certain scenarios can lead to the simultaneous instantiating and destruction of a multitude of objects. This isn't a rare occurrence, these specific situations happen often. What I ended up doing to improve this is the following:
To take this further, I pre-populate my arrays with about 8 items each. All of these instances are created while the level is loading, and not during play. Now, Instantiate only executes if all 8 of any given type are currently in use. Then the newly instantiated rocket adds itself to the array, increasing the pool from 8 to 9. I've gone from a ridiculous amount of Instantiate and Destroy calls to a rare Instantiate and no Destroy calls.
My ammunition, my enemies and items all get recycled into their appropriate arrays that serve as an availability pool. Doing this has greatly increased my performance on lower end devices. While the slow down wasn't noticeable on my desktop, frame rates dropped dramatically with heavy action on my laptop. That is no longer the case. I still have a few other areas I need to optimize, but transitioning my code and logical thinking to this idea has already shown its benefit. As I clean up and optimize other areas, I'll be sure to write up more posts.
It seems odd to me, that adding/removing from an array is better for performance than rapidly instantiating and destroying game objects. When I pull something from the array, I'm copying it to a variable. Isn't that an instance? Likewise, when I remove the copy from the array, isn't that destroying? I'm not directly using the functions, but I would think it's the same concept.
To better answer these questions, I may try a solution that does not require copying game objects to variables and changing the array size. As an example, if I were to loop through the array, and simply use the first game object that isn't already in use, I could probably achieve the same effect. The the question then becomes "is looping through an array of objects every time an item is used more costly than my current solution?" Only one way to find out. I'll update this thread if I'm able to get better results on this issue.
If you're reading this and thinking of better solutions - I'd love to hear about them. I encourage you to leave your thoughts in the comments. I love constructive input that serves to make better games.
I hope this helps some of us, and thanks for reading!