bfops
bfops

Reputation: 5678

Game Collision-Handling

The code given is for example purposes, not copypasta from my codebase

I'm writing a primitive, cross-platform Snake game in C++ with Boost & SDL, and I'm wondering what the best way to implement collision-handling is (not collision-detection). So far, I've been using a single-dispatch idea, with ugly spaghetti code, like so:

void Snake::CollisionHandler(const WorldObject& obj)
{
    // collided with self
    if(obj.GetObjectType() == snake)
        Die();
    ...
    ...
}

Also, I have a "global" collision handler, which does things involved in a collision, which are independent of each object, for example:


void GameWorld::CollisionHandler(WorldObject& obj1, WorldObject& obj2)
{
    if(obj1.GetObjectType() == snake && obj2.GetObjectType() == snake)
        PlayDeathSound();
    ...
    ...
}

To avoid things like sounds being played twice for collisions.

I've also considered double-dispatch, like so:


void Snake::CollisionHandler(WorldObject& obj) const
{
    // invoke obj's collision handler with a const Snake& parameter
    obj.CollisionHandler(*this);
}
// collided with self
void Snake::CollisionHandler(const Snake& obj)
{
    Die();
}

This also includes a similar global collision handler like above.

Then there's the approach of only having a global collision handler (which is a friend function to all game objects), like so:


void GameWorld::CollisionHandler(WorldObject& obj1, WorldObject& obj2)
{
    // snake collided with self
    if(obj1.GetObjectType() == snake && obj2.GetObjectType() == snake)
    {
        obj1.Die();
        obj2.Die();
        PlayDeathSound();
    }
    ...
    ...
}

Are there any strategies I'm missing? Which of these ends up being the nicest? They all seem to have some ugly code involved, and the single- and double- dispatch ones involve polymorphism, which I personally try to shy away from.

Upvotes: 9

Views: 4108

Answers (2)

Gareth Rees
Gareth Rees

Reputation: 65854

Collision handling is an area where C++/Java-style object orientation (with single dispatch) is not flexible enough. The result of a collision depends on the types of both colliding objects, so you need multiple dispatch to handle it. (It's no coincidence that the motivating example on Wikipedia's multiple dispatch article is collision handling!)

I think that a global collision handler that then dispatches to individual object methods is the best workaround for this inadequacy in C++.

Upvotes: 5

stnr
stnr

Reputation: 455

IMO the last approach of letting the game class completely handle collisions and other global events is the wisest and possibly the most "correct" way of doing it.
For example take a chess program. It is pretty obvious that the game class should handle the case of win or lose by one of the players, and not the player class.
It is also more more effective practically. Think of a case where you want to add more classes (e.g another type of snake), instead of duplicating code or overriding CollisionHandler you can just let the game class handle it with much less effort.

However, if your only purpose is a simple snake game it is probably not that important how you choose to implement it.

Upvotes: 1

Related Questions