Sign in to follow this  
Fire Lancer

game structure question

Recommended Posts

I was wondering whats a good way to keep track of the diffrent objects, and allow efficent interaction between them (eg collision testing). My current plan is to have a base "Entity" class, then derive from that, with each class tracking all instances of that class and upadte it as things are destroyed/created.
class Entity
{
    static std::set<Entity *>Instances;
    virtual void Update()=0;
    virtual void Render()=0;
};
class Projectile : public Entity
{
    static std::set<Projectile *>Instances;
    virtual void Update();
    virtual void Render();
};


Theres a couple of problems here I can see: * Creation/desttruction of objects during update could be dangerous, since doing so invalidates the iterators (eg the one iteracting Entity::Instances). The solution I can think of for this is to have two global lists, created and destroyed, and use those to update the lists for each class after the update. * This could result in quite a few sets, where a single instance may need to update several of them. Would adding/removing instances be too slow and become a bottleneck? * Theres alot of simeler code that I need to write for every object and rember to update if I cahange something (eg the method for adding/removing the instance from its sets). Is there somthing in/for c++ that could handle such code for me? However also some goods points * Collision detection can be done simply by testing the contents of one list (eg Projectile::Instances, with another eg Ships::Instances) * Easy to get all the instances of a certain class, wich is needed for lots of game logic (eg a turret needs to be able to find all the Ships instances, in order to determin a target). Is this generaly the beset way, or is there another, far better design for this?

Share this post


Link to post
Share on other sites
Keeping a set of all instances for each type will probably quickly grow out of control. Unless you really need to optimize it due to performance issues, I'd recommend placing all entities in a container for all entities in the level. If you then need to find entities of a certain type, look though them all and cast them to the type you are looking for. Its not optimal, but unless you got a quite large amount of entities, you're not going to notice a difference.

Regarding removal of entities. Add a bool to the base class signaling if the entity should be destroyed before the next update, then loop though all entities and remove marked ones at an appropriate time.

For collision, once again, unless you have a large amount of entities, check each entity against every other entity. With a sphere, or bounding box test before any more complex tests it should be acceptably quick. Otherwise you can consider adding a spatial subdivision scheme for finding entities close to one another.

Share this post


Link to post
Share on other sites
You're on the right path.

I tend to avise using a list for every general type of object, and put each object into a single list. That is, you wouldn't have a "list of entities" nor a "list of pink bullets", but a "list of projectiles".

This eliminates the "add object to several lists" issue, while still allowing to virtually group several lists into one (for instance, all AI opponents and all player characters into a single "characters" list) using an approach similar to SQL views (such as creating an iterator that can iterate through several lists).

Share this post


Link to post
Share on other sites
Quote:

such as creating an iterator that can iterate through several lists

How exactly do I go about making an iterator which can iterate through several lists, while keeping it compatable with normal iterators?

Well the sets for diffrent "types" of objects seem a good idea, although many will derive from common class (eg both projectiles + ships share the same movemnt code, using vectors).


std::set<Ship*>ships;
std::set<Projectile*>projectiles;



I suppose for collison testing I could just test everything in certain sets against averything else, and include some stuff to exit the test early...

template<class A, class B>bool CollisionTest(A *a, B *b)
{
if(Allied(a,b))
return false;//allied objects can't collide
if(dynamic_cast<Projectile*>(a) && dynamic_cast<Projectile*>(b))
{
if(!
(((Projectile*)a)->isPD() && (((Projectile*)b)->isDestroyable())
||
(((Projectile*)b)->isPD() && (((Projectile*)a)->isDestroyable())
)
return false;//collision between projectiles only has meaning for between pd, and destroyable projectiles (like missiles)
}

//collision test here
}


Share this post


Link to post
Share on other sites
Quote:
Original post by Fire Lancer
How exactly do I go about making an iterator which can iterate through several lists, while keeping it compatable with normal iterators?
Depends on what you mean by 'compatible'. The idea is that, if you want to process all renderable objects, you don't care about anything except getting all of them processed. So, you don't care, for instance, about what list they are in.

In that case, you can create a polymorphic enumerator by defining an interface with "Next" and "Value" functions and implementing it for arbitrary (begin,end) pairs of any type (as long as you can static-cast the values to the appropriate type (for instance, "projectile" to "renderable"):
template<typename It, typename Out> class Enumerator : public IEnumerator<Out>
{ /* Implement */ }


Then, you can create a 'view' object which stores a list of such enumerators polymorphically, and implement Input Iterators with that object by having the iterators move to the next enumerator once they reach the end of the current one.

As a side note, be careful about mixing up logic elements. For instance, in your collision testing function, you don't want to check whether two objects are allied: you want to check whether two objects can collide (which just happens to be, right now, when they are not allied). So, the correspondence between "are allied" and "cannot collide" is not implicit in the collision detection code, but instead isolated cleanly somewhere else.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this