Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm having a problem with the way I designed my first simple game in C++.

I have GameObject (abstract class) and ObjectA which inherits the update() and draw() methods from GameObject.

My main loop contains a linked list of GameObject*, and while that list is not empty it cycles through it, calling update on each one.

Up until this point, I thought the design was standard(?) and would work.

However, when I call update on ObjectA() I run into two problems:

  • ObjectA can die which messes up the list, which in turn throws off the loop in main.
  • ObjectA can spawn more ObjectA's but these are local scope and the update() goes out of scope, creating problems in main's list of GameObjects.

I think my design if alright, but I'm having such problems with segmentation faults that there must be something seriously wrong with at least one part of my implementation. If anyone could point out any serious mistakes or simple examples of this being done (or even alternative designs) then I would greatly appreciate it!

share|improve this question
3  
How much C++ experience do you have? This sounds like you're having basic problems with the language (pointers, scope). If you're eager to start game programming, you might want to start with a higher-level language, or otherwise practice/learn C++ a bit more. You have to crawl before you can walk, eh? –  Ricket Apr 26 '11 at 4:07
    
I'm used to C in that you malloc whatever dynamic memory you need, but C++ has confused me a bit in that I'm not completely sure when I should be using new. Even if I do use new when constructing ObjectA's, would it be better to use new for every object I instantiate? –  oisin Apr 26 '11 at 4:09
    
new is the same as malloc, just properly typed. –  DeadMG Apr 26 '11 at 11:58
2  
(And calls a constructor. And requires different forms of delete. And may be overloaded.) –  user744 Apr 26 '11 at 20:43

3 Answers 3

Actually why not use a vectors standard methods to add and remove objects? Basically its just an array of pointers to objects and when an object needs to die you simply remove it and the vector will decrease its size automatically. The nice thing is that you have a base class "Object" lets say and it doesnt matter to the vector what the derived types are as long as they are inherited from Object. This allows you to call update() draw() regardless of the objects type.

std::vector<Object *> objects;  // Your list of pointers to objects

When one needs to die:

void ObjectManager::destroy(Object *o)
{
    for(int i=0; i<objects.size(); i++)
          {
             if(objects[i] == o)
                {
                   objects[i]->destroy();  // Define virtual method destroy 
                   delete objects[i];      // Delete the pointer (create with new)
                   objects.erase(objects.begin() + i);  // Erase from vector!
                   return;
                }


          }
}

I hope this helps (albeit a year late lol). The destroy method is a good idea because derived classes wont have their destructors called when called through a base class pointer like this unless you define the destructors as virtual. Having default constructors should be fine depending on how you designed your objects but you could use an init() function as well that is virtual.

share|improve this answer

The solution is to iterate in reverse from back to front. That way, if you: 1. Add things to the end of the list, it won't get iterated upon 2. The currently-iterated thing dies, the loop can still continue as normal

If I were you, I'd use a vector class and iterate backwards using numeric indices. (e.g. for int i = things.size() - 1; i >= 0; -- i)

share|improve this answer
1  
This is great advice, thank you! –  oisin Apr 27 '11 at 4:49

First off, don't use linked lists.

Second, your design should work, in theory. For the dying problem, an easy solution is to just have some kind of flag on your GameObject class that says whether or not the object is dead. Just set it in your concrete classes' update method when appropriate. Then after all of your updates are complete, remove the dead objects from the object list.

So in theory something like this (excuse my C++ it's been a while):

for_each( m_allEntites.begin(), m_allEntites.end(), mem_fun( &GameObject::update ) );
remove_if( m_allEntites.begin(), m_allEntites.end(), mem_fun( &GameObject::isDead ) );
for_each( m_allEntites.begin(), m_allEntites.end(), mem_fun( &GameObject::draw ) );

Third, for your "new game objects" problem. What you want to do is use new on the ObjectA objects you create. If you can't modify the list while you're iterating over it, an easy solution is to create a temporary list (or vector, whatever) with the new objects you've created. Then when you're done with update, add the new objects to the list of all objects. A naive solution would just be that all GameObjects know about the class that contains them, but I wouldn't worry about the coupling that imposes at this point in time until you figure out the basics. So in your class that contains the list of all objects, and modifying the above structure, you can do something like this:

for_each( m_allEntites.begin(), m_allEntites.end(), mem_fun( &GameObject::update ) );
m_allEntites.insert( m_allEntities.end(), m_newEntities.begin(), m_newEntites.end() );
m_newEntites.clear();
remove_if( m_allEntites.begin(), m_allEntites.end(), mem_fun( &GameObject::isDead ) );
for_each( m_allEntites.begin(), m_allEntites.end(), mem_fun( &GameObject::draw ) );

Edit: Just realized previous code would leak dead objects. I'm used to using ptr_vector instead of standard vector to maintain strict ownership rules. Using a standard vector you'd want to iterate over the list and delete dead objects. A common pattern I've used in the past was to also set their pointer to null then do a remove_if on null objects. Or you could do something fancy and keep GameObjects around in a bucket pattern to avoid allocations if that's the route you wanted to go down.

share|improve this answer
    
I thought a linked list would be better than a vector since because each GameObject holds a reference to the vector/list, I wouldn't want it moving around. This way I can just hold the address to the front of the list which remains stationary. –  oisin Apr 26 '11 at 5:00
    
The vector isn't going to "move around". The address of the 0th element will move as the vector gets resized, but the vector object itself isn't going anywhere. &myVec != &myVec[0]. Besides, you'd probably want a reference to the world class or whatever you're calling it that actually contains the vector and is calling update and draw. –  Tetrad Apr 26 '11 at 6:53

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.