Slowdown with rapid spawning and removing

Topics: Developer Forum
Aug 17, 2007 at 4:34 PM
I'm making a game in the likes of Geometry Wars, but the game slows down after I spawn and kill large numbers of objects repeatedly.

I did the obvious thing and used EntityManager.Add(newEntity) for spawning and EntityManager.RemoveAt(index) for removing (and likewise for SceneManager). Regardless, when I run the game and fire a motherload of bullets at the walls (which destroys them) the game will get progressively slower as the computer adds new chunks of data to the ArrayLists. Is this just a weakness of ArrayLists that I'm forced to cope with, or is there a way to fix this?
Coordinator
Aug 17, 2007 at 4:45 PM
I can't remember how the entity manager works and I don't have the code infront of me but is sounds like the underlying rigid bodies are not being removed from the enigne. Just because you removed the entity doesn't mean the rigid body was removed from the engine. Look at the code and make sure when you are done with an entity you dispose the underlying rigid body and then remove the entity from the manager.
Aug 17, 2007 at 7:53 PM
Edited Aug 17, 2007 at 9:33 PM
Oh, there's a Dispose() function? Oops.

Is there an equivalent for the SpriteEntityView, too?

Now that I've changed the way entities are disposed of, the game lasts 20% longer before slowing to a crawl (10 seconds instead of 8 when a new object is spawned every frame).

Here's now I'm disposing of objects now:

PolygonEntity.Dispose();
PolygonEntity.RigidBody.Dispose();
SceneManager.RemoveAt(index);

Except PolygonEntity is called something else.

EDIT: I take that back. I've noticed that the slowdown I experienced after the change occurs only when I'm spawning new entities; once I stop firing, it's silky-smooth again. I wonder what's causing it...

Think it could be my rapidly-expanding SpriteBatch? 'Cause I'm guilty of calling LoadGraphicsContent(true); every time a new object is added.
Coordinator
Aug 18, 2007 at 11:31 AM
I think the slow down is due to the engine needing to pre-compute the distance grid when the new body is created. You should create a pool of "bullets" and pre-initialize as many as you think you will need at once. Then, when you fire just pull an object from the pool, position it, add it to the enginge, and apply the necassry force to fire it. Then, when you are done with the bullet, remove it from the engine and add it back to the pool without Disposing of it. This way you won't need to re-initialize it which recreates the distance grid.
Aug 18, 2007 at 5:35 PM
Edited Aug 18, 2007 at 6:07 PM
I just figured out my problem: when I added the Dispose() functions to my code, I figured I would have no use for EntityManager.RemoveAt(index);. *slaps forehead*

Although I probably ought to make an Array of bullets anyways as a way of optimizing my code.

Thanks for the help. You rock!
Oct 7, 2007 at 5:12 PM
Edited Oct 7, 2007 at 5:16 PM
I don't know if this is the best method, but what I do when spawning and despawning large numbers of objects is to use an ArrayList of the objects, give them an enabled/disabled attribute, and maintain a queue of reusable indexes. Basically, if the queue is empty, add a new object to the end of the ArrayList (I set a reasonable capacity at the start). If it isn't, pop an index off the queue and reuse that object in the ArrayList. When you despawn an entity, disable it and push its index onto the queue. It seems to work well for me. Depending on the despawn logic, a stack might work better than a queue. Generally you want smaller indexes to be reused first, as you will waste time skipping disabled entities if you are iterating through your ArrayList. You can always insert despawned indexes into an ordered list (so you will always reuse the smallest index), but you are balancing despawn speed vs ArrayList iteration. Which is more important depends entirely on the specifics of your game. In practice, I've used this method to fire multiple bullets per frame with up to 10,000 bullets on the screen at a time (in a stress test). The method works extremely well with constant despawn intervals and reasonably well with varying despawn intervals.

-Jeremy
(edit: I forgot to mention that you also keep track of the last enabled index, so you don't have to iterate through the entire ArrayList, for example if you only have 20 bullets left onscreen after firing 10000 a few seconds ago).