Removing Creatures from the simulation is as important a part of natural selection as creating them, so let’s take a look at data structures and how they relate to murdering creatures for fun, profit and natural selection.
WARNING: this post contains programmer talk. The blog author will not be held responsible for any hitherto unknown allergic reactions to computer geekery.
Games Programming can be a funny thing. See, the simplest, sanest way to make new objects is, well, to make new objects. I want a creature to give birth to a second creature? Easy: simply call “new Creature()” and add the newborn to the list. Likewise, if I want to kill a creature and remove it from the game? Call Remove(). Also easy! What could go wrong?
Well, in C++, this wouldn’t be an option. C++ makes you manually dispose of objects: so, rather than just removing my creatures from the list, I’d have to make sure to dispose of them and all their references as well. If I didn’t they’d persist in memory and clog up the machine over time.
But .Net, (and by extension, C# and XNA) is smarter than that: it has the Garbage Collector, a marvellous piece of technology which detects and removes unreferenced objects, such as our dead Creature.
So yay! All good, we can get on with the gruesome murder, right?
Wrong! Also, slightly morbid.
See, the Garbage Collector takes time to dispose of objects, and if you’re generating a lot of garbage, say by (to take an example entirely at random) simulating an entire population of rapidly living and dying creatures, that time can add up. You’ll start to notice frequent ‘spikes’ in your frame-rate: frames that take much longer than your usual frames, happening every time the garbage is collected. How bad this is depends on your platform: I’ve not developed for the XBox 360, but I’ve been told it is utterly terrible at Garbage Collection.
But I’m developing for PC, so that’s not as much of a problem. The Windows Garbage Collector is actually quite fast. So, off we go to murder- *smack* Ow! Okay, okay, I’ll stop.
The windows garbage collector is fast, but it isn’t that fast, and for Species CPU time is at a premium. More free CPU time means more creatures, better frame rates, all that good stuff. So the ideal is not to handle any garbage at all, and for that what I need is a way to handle creatures being born and dying without actually creating and disposing of them.
And for that, I need an object queue.
The theory is simple: rather than creating and disposing of Creature objects on the fly, I create the maximum number (1500, currently) of creatures right at the start of the program, and don’t dispose of them until the very end. When a creature dies it isn’t removed: the object just goes into stasis until it’s needed again, at which point it is reincarnated as a completely different creature. Ergo: the Species universe runs on Buddhist philosophy.
Obviously the memory footprint of maintaining 1500 dead creatures is quite large, but it’s no bigger than that of occasionally having 1500 alive creatures, and an old maxim states: your performance is no better than your slowest frame rate (okay, it’s not that old as far as maxims go): I guess the same applies to memory footprint? Maybe? And in the long run, memory is far less valuable real estate than CPU time anyway, so it was definitely worthwhile doing.
So, with all that sorted out: creatures can now die. By which I of course mean “vanish mysteriously”: proper corpsing wasn’t implemented until some time later.
Oh, and for anyone wondering, yes: the very first thing I did after this was make a “murder everyone” function. I swear I did it for debug purposes though, and not at all so that I could sit at my computer laughing manically while continually committing horrific genocide against the hapless population.
Oh don’t give me that look, I know you all did the same thing in SimCity.
Gah! My allergies!