Jump to content
  • Advertisement
Sign in to follow this  
Acetate

Handling a collection of short-lived objects

This topic is 3156 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I'm looking for some advice about design and implementation. My class design currently resembles the following, first an abstract base class:
class Actor // abstract
{ ... };
And its specializations to be instantiated:
class ActorType1 : public Actor
{ ... };
class ActorType2 : public Actor
{ ... };
The (only) differences between these two are: - their speeds; - the way collisions are handled. Those actors have a rather short lifespan and need to be created and destroyed fairly often. Furthermore, there is a lot of them present at the same time. I'm having a hard time trying to decide which solution would be best here, between: - a collection of pointers or shared_ptrs allocated and deallocated for every birth and death; - a collection of pointers or shared_ptrs never deallocated until the end, with a kind of isValid flag to help sort 'null' actors; - no polymorphism (hence no child classes): a collection of Actor objects with a kind of isValid flag. The two different types of actors are handled 'the dirty way'. I'm finally lending towards the last solution but which one would you choose? Of course if you're thinking of a solution that I might have overlooked, feel free to share! Thank you.

Share this post


Link to post
Share on other sites
Advertisement
You want to avoid as much allocation and deallocation at run-time as possible so usually option 1 is out.

What you could do is when an object "dies" it just goes into a separate list(note I don't necessarily mean linked list, just something to hold "dead things"...wow that sounds even worse) and when a new object needs to be created just grab one from that dead list. That way when you only iterate over your living objects and not having to check to see if they are alive.

Share this post


Link to post
Share on other sites
Guest
Well, whatever method you may chose, do NOT allocate and free objects per frame.

Since you say the only differences between those actors are just speed and collision method, my first thought would be to unify them in one single class (or structure) and allocate an array of that class (only once, in some init function at the begining of the level or game). Then just activate / deactivate them when creating / destroying an actor, same as in a particle tank.

Share this post


Link to post
Share on other sites
Another option is to use a pooled allocator of some sort (e.g. boost::pool if you're programming in C++). This will lessen the cost of per-update allocations and deallocations, while still allowing you to initialize the object's state via the constructor (and to make use of C++ idioms such as RAII).

Share this post


Link to post
Share on other sites
Do you know that it will be a problem? I would suggest that you make something with simple design first. Something like


class ActorPool {
public:
enum ActorType { TYPE_1, TYPE_2 };
Actor * create(ActorType type) {
if (type == TYPE_1) return new ActorType1;
return new ActorType2;
}
void release(Actor * actor) { delete actor; }
}


IF you then run into performance problems due to new/delete, then you can rewrite the actor pool class to use some form of pooling. You can even use this abstraction to test different pooling algorithms to see how you ken tweak the memory/performance.

That being said, you will probably get most performance out of skippig polymorphism. If you only use one "super class" to handle all subclasses then methods may be inlined. By combining them you can then end up with something like this:


class ActorPool {
public:
enum ActorType { TYPE_1, TYPE_2 };
Actor * create(ActorType type) {
if (m_pool.empty())
return new Actor(type);
Actor * result = m_pool.back();
m_pool.pop_back();
result->setType(type);
return result;
}
void release(Actor * actor) { delete actor; }
private:
std::vector<Actor *> m_pool;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Acetate
- the way collisions are handled.


To handle collision between two actors A and B - what data do you need?

Share this post


Link to post
Share on other sites
Quote:
Do you know that it will be a problem? I would suggest that you make something with simple design first.


This. Basically, it's not really worth spending much time optimizing this and making the design more obscure unless you for sure now this is the bottleneck.

Only things I ever optimize ahead is when I can accurately calculate the resources required (e.g. for a 1024x1024x128 3D grid each cell is going to have a pretty tight memory limit and warrant optimization from the start).

Share this post


Link to post
Share on other sites
Short-lived, created and destroyed often, there are a lot of them, basically sounds like particle system optimization.

There was just a a few months back where someone implemented particle systems in multiple ways. IIRC the performance hit for allocating/deallocating particles was about 50%. So basically, if there are going to be many short lived objects(as in hundreds), you want to pre-allocate them all, use some type of active/inactive flag to spawn or despawn them.

Share this post


Link to post
Share on other sites
First, I would like to thank everybody for all these useful replies.

I think I will go for a simple pool, that is a container of shared_ptrs. I don't know yet how many actors can exist at once so the pool will have to extend the container if it's needed. It's not a particle system but thinking about it the behaviour should be fairly similar.

Regarding the class design: I was not looking for performance, rather for an elegant OO-style. But I agree with you all, I think it's better in this case to unify the classes and use an enum to implement types.


Quote:
Original post by AntheusTo handle collision between two actors A and B - what data do you need?


Well I just need their AA boxes (position + dimensions) to detect the collision but I don't need anything to handle it, basically the actor is either killed or not. The difference is so thin that it's probably not worth using polymorphism eventually.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!