1
\$\begingroup\$

I am looking for a way to avoid the dreaded switch or if/else scenarios between numerous game object types when a collision takes place in a game. For example:

You have a list of game objects which inherit from a common class such as GameObject. You check the list for any collisions and call a method for each colliding object to respond to the collision, but this situation develops:

public void handleCollision(GameObject other) {
    switch(other.getType()) {
    case Alien:
    //Perform some logic
    break;

    case Ogre:
    //Perform some logic
    break;

    case Wall:
    //Perform some logic
    break;

    case Door:
    //Perform some logic
    break;

    //and so on

    }
}

This would become unwieldy with hundreds of different game object types. What I was attempting to do was this:

Map<CollisionKey, Method> collisionCallbackMap = new HashMap<CollisionKey, Method>();

collisionCallbackMap.put(new CollisionKey(gameObjectType, gameObjectType), //add a reference to a method here);

CollisionKey is a class I created for handling game object pairs such as Player-Alien, Player-Ogre, Player-Wall, etc. The idea was to look up a pair of game objects in the map, cast the game object in the collision list to the appropriate class types, and pass them into the method stored in the value slot of the map for that game object pairing. So it would look something like this:

for(GameObject a : collisionListA) {
    for(GameObject b : collisionListB) {
        if(a.collidesWith(b)) {
            collisionCallbackMap.get(new CollisionKey(a.getType(), b.getType(), //cast GameObjects to appropriate types such as Player and Alien and pass it into a method here);
        }
    }
}

The method called from the map would look something like this if the game objects colliding were a Player and an Alien:

public void playerToAlienCollision(Player p, Alien a) {
    //Perform some logic here such as...

    p.reduceHealth();
    a.reduceHealth();

    a.knockBack();
}

This wouldn't be a problem if I were working in, say, C++ with function pointers, but I'm working in Java with Android. Android's Java only supports Java 6, and if I'm not mistaken I believe it now has support for Java 7, but it does not currently support the recently released Java 8. With the addition of lambdas and method references in Java 8 I feel this would be a viable approach, but I don't have access to that so I need another solution. The workaround or Java's version of function pointers before Java 8 seems to involve interfaces with a single method and I believe I would need one for each collision method. It just looks convoluted and not very polished. The accepted answer of this question displays an example of it:

https://stackoverflow.com/questions/4480334/how-to-call-a-method-stored-in-a-hashmap-java

I'm not looking for how collision detection is done, I'm ok with that, its what comes right after I'm seeking a solution for. What is an efficient way to handle collision response and callbacks without the dreaded and bloated switch or if/else scenarios? I think of a large game like Runescape with tons of objects and its written in Java and wonder how they set up their collision response/callbacks.

\$\endgroup\$
2
\$\begingroup\$

Use interfaces (available in Java 6).

If all objects collide under the same loop, then you can have them all implement the same functions but perform different logic.

ICollidable{
  bool CollidesWith(ICollidable other);
  void handleCollision(ICollidable other);
  void reactToCollision(ICollidable other);
}

GameObject implements Icollidable {
  ...
  void handleCollision(ICollidable other){
    this.reactToCollision(other);  // calls reduceHealth();
    other.reactToCollision(this);  // calls knockback();
  }
  ...
}

The gist of this is that java doesn't need function pointers. It has something better.


Aside 1: if you attempt to write functions like this:

public void playerToAlienCollision(Player p, Alien a)

You haven't solved the "dreaded switch or if/else scenarios", you've only relocated it. You still have to write n^2 functions to accomplish collisions, where before you had to write n^2 switch cases. If each object is responsible for its own behavior during a collision, you only have to write n implementations of the interface. Also, you avoid global function declarations that need tight coupling to both classes.


Aside 2: if you detect collisions like this:

for(GameObject a : collisionListA) {
  for(GameObject b : collisionListB) {
    if(a.collidesWith(b)) {
      ...

Then you have not yet mastered the art of detecting collisions, either. But thank you for explicitly excluding that topic from your question.

\$\endgroup\$
  • 2
    \$\begingroup\$ This use of an interface still seems to leave the scenario of a large switch statement if you have many game objects. Once you get inside the reactToCollision method, you would still need a switch to identify which type of object is being reacted to. A player might react to an alien one way, an ogre another way, a door another way, and so on. Is this a pick your poison situation between a large switch statement or a large of amount of collision methods? \$\endgroup\$ – Red Mar 24 '14 at 22:34
  • \$\begingroup\$ On a side note, the collision detection displayed in the question is rudimentary for the sake of brevity and I feel I have a decent understanding of it, not mastered though. I would love to hear your take on it whether its through an e-mail or directing me to a source. \$\endgroup\$ – Red Mar 24 '14 at 22:36
  • \$\begingroup\$ Well, if you absolutely have to have different logic, then you really can't avoid writing that different logic. So yeah...pick your poison. My answer is a little optimistic in assuming you can abstract the behavior of each object into functions that don't need to know implementation details of other objects. But in your case, it might be impossible. --- I appreciate your short example collision loop; we've all implemented crappy O(n^2) stuff before. It is certainly a topic unto itself, and there'are lots of questions about it here. \$\endgroup\$ – Seth Battin Mar 24 '14 at 23:06
  • \$\begingroup\$ Thanks for your input. I always seem to be rummaging through collision detection and game development related questions/articles on the stackexchange websites and around the web and I'll continue to do so. \$\endgroup\$ – Red Mar 24 '14 at 23:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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