Question

I am programming a simple 2d game engine. I've decided how I'd like the engine to function: it will be composed of objects containing "events" that my main game loop will trigger when appropriate.

A little more about the structure: Every GameObject has an updateEvent method. objectList is a list of all the objects that will receive update events. Only objects on this list have their updateEvent method called by the game loop.

I’m trying to implement this method in the GameObject class (This specification is what I’d like the method to achieve):

/**
* This method removes a GameObject from objectList.  The GameObject 
* should immediately stop executing code, that is, absolutely no more
* code inside update events will be executed for the removed game object.
* If necessary, control should transfer to the game loop.
* @param go The GameObject to be removed
*/
public void remove(GameObject go)

So if an object tries to remove itself inside of an update event, control should transfer back to the game engine:

public void updateEvent() {
    //object's update event
    remove(this);
    System.out.println("Should never reach here!");
}

Here’s what I have so far. It works, but the more I read about using exceptions for flow control the less I like it, so I want to see if there are alternatives.

Remove Method

public void remove(GameObject go) {
    //add to removedList
    //flag as removed
    //throw an exception if removing self from inside an updateEvent
}

Game Loop

for(GameObject go : objectList) {
    try {
        if (!go.removed) {
            go.updateEvent();
        } else {
            //object is scheduled to be removed, do nothing
        }
    } catch(ObjectRemovedException e) {
        //control has been transferred back to the game loop
        //no need to do anything here
    }
}
// now remove the objects that are in removedList from objectList

2 questions:

  1. Am I correct in assuming that the only way to implement the stop-right-away part of the remove method as described above is by throwing a custom exception and catching it in the game loop? (I know, using exceptions for flow control is like goto, which is bad. I just can’t think of another way to do what I want!)

  2. For the removal from the list itself, it is possible for one object to remove one that is farther down on the list. Currently I’m checking a removed flag before executing any code, and at the end of each pass removing the objects to avoid concurrent modification. Is there a better, preferably instant/non-polling way to do this?

[Edit] After reading your answers, I think I'll change the method specs. The instant-remove behavior is something I’ve become used to working with in a different engine, but you’re right, it doesn’t really fit in with how Java works. Time to go try to wrap my head around a slightly different method of thinking!

Was it helpful?

Solution

Why not simply return, i.e.,

public void updateEvent() { 
    //object's update event 
    remove(this); 
    return;   
    //obviously unreachable 
    System.out.println("Should never reach here!");     }

OTHER TIPS

I agree that the exception approach is the best way to implement the remove method according to your specification.

However, maybe you should reconsider the specification. I would leave the decision of when updateEvent terminates to the implementor. Termination with the remove() call is confusing, and requires usage of exceptions for flow control. I believe that the call to remove() should only change the flag state. And I see no real problem with looping over all objects, checking the removed flag for each of them.

Why don't you just:

  • Maintain the objectList in the object that runs the loop
  • Don't let the GameObjects have access to the list (why should they?)
  • Have the updateEvent function return a boolean. If the return value is false, the parent object removes that object from the list of events. The return statement also serves to terminate execution of the event function.

@jball's answer is great-- +1.

Another method I've used that works well and might be slightly cleaner is to have your updateEvent() method return a boolean. Whenever a True is returned from updateEvent, you remove() the object.

This allows your event loop to have more control over how the loop itself is executed and removes a little bit of unnecessary binding between your classes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top