1
\$\begingroup\$

In a game I'm working on, there's a class responsible for collision detection. It's method detectCollisions(List<Entity> entities) is called from the main gameloop.

The code to update the entities (i.e. where the entities 'act': update their positions, invoke AI, etc) is in a different class, in the method updateEntities(List<Entity> entities). Also called from the gameloop, after the collision detection.

When there's a collision between two entities, usually something needs to be done. For example, zero the velocity of both entities in the collision, or kill one of the entities.

It would be easy to have this code in the CollisionDetector class. E.g. in psuedocode:

for(Entity entityA in entities){
    for(Entity entityB in entities){
        if(collision(entityA, entityB)){
            if(entityA instanceof Robot && entityB instanceof Robot){
                entityA.setVelocity(0,0);
                entityB.setVelocity(0,0);
            }
            if(entityA instanceof Missile || entityB instanceof Missile){
                entityA.die();
                entityB.die();
            }
        }
    }
}

However, I'm not sure if updating the state of entities in response to collision should be the job of CollisionDetector. Maybe it should be the job of EntityUpdater, which runs after the collision detection in the gameloop.

Is it okay to have the code responding to collisions in the collision detection system? Or should the collision detection class only detect collisions, report them to some other class and have that class affect the state of the entities?

\$\endgroup\$
  • \$\begingroup\$ this kind of O(N^2) complexity will get your game on the floor passed 60/70 objects. If its ok then good. If you will have more objects, then you need to start using a space partitionning structure and in the inner loop, instead of checking "all others" you check "all near". \$\endgroup\$ – v.oddou Sep 11 '14 at 6:12
  • \$\begingroup\$ @v.oddou Yep, in my next games I'm planning to implement a uniform grid to divide the screen into cells. Than I check for each entity if it collides with whatever in it's cell, not everything on the screen :) \$\endgroup\$ – Aviv Cohn Sep 11 '14 at 6:49
1
\$\begingroup\$

Well, CollisionDetector sounds like a pretty generic class name and I guess you might want to re-use it for other games as well. Adding game-specific logic like if(entityA instanceof Robot .. really defeats that purpose unless every game will have a Robot class...

I'd let the entity decide what to do when a collision happens. So your entity base-class or interface could have a OnCollision method which will then be called by your CollisionDetector. Usually you'll pass the object that collided with the entity and some other relevant information (maybe contact-points) as parameters to the callback.

You tagged your code as pseudo-code, so I'm not sure how close to reality it is, but right now you're checking every collision twice (because of the two for loops).

\$\endgroup\$
  • \$\begingroup\$ Is having each entity decide for itself how to react to a collision standard? Is this how it's usually done? \$\endgroup\$ – Aviv Cohn Jun 12 '14 at 20:41
  • 1
    \$\begingroup\$ @Prog It really depends. Sometimes you have a physics-engine that resolves collisions and updates all the forces and velocities for you. Then you can use collision-listeners or callbacks on your entities to do the game-related logic (eg. mark an entity as dead or play a sound effect). It really depends on your game architecture but having collision callbacks is something that's being widely used. \$\endgroup\$ – bummzack Jun 12 '14 at 22:40
  • \$\begingroup\$ I have a question: I like the idea of moving the collision-handling to the classes themselves, instead of having them at a central place. However what I don't like is that I'm going to need a lot of ifs and instanceofs in the collision handling. For example a Robot might want do die if hit by a missile, but jump if hit by a dog, etc.. So it's handleCollision(Entity e) method would probably look something like {if(e instanceof Dog)jump(); if(e instanceof Missile)die() ..etc}. This is very ugly and not very OO. What's the common way to avoid this? \$\endgroup\$ – Aviv Cohn Jun 15 '14 at 15:52
  • \$\begingroup\$ Reverse your logic. Don't handle collison and check what hit you. Handle collision and tell the other thing what you do to it. All objects create and receive these abstracted types of messages like "animal bite" or "fiery explosion" and then each object class decides what to do with that information. In this case Robot gets "animal bite" and jumps. For the future this is a perfect place to add scripting so all this reaction logic can be changed without having to write program code and rebuild the application. \$\endgroup\$ – Patrick Hughes Jul 12 '14 at 22:17
  • \$\begingroup\$ Each of these questions goes further in the right direction (at least to this reader, and the other commenters :) ). Each of these questions untangles and moves the ifs and instanceofs further away from the initial question about baking it all right into the collision detector. @Aviv, your line of reasoning is totally on target. Go for it. But remember you can't abstract forever; eventually the rubber hits the road. Someone does something based on their class. Maybe not by instance of, but, heck, sometimes, maybe. \$\endgroup\$ – david van brink Oct 11 '14 at 6:27
0
\$\begingroup\$

You can send messages to each entity in the collision, containing the collision_type of the other object, it's mass and velocity at the time of collision, and the contact point on the messaged entity. Entities handle the messages for collision_types they want to respond to, and ignore the others.

Also, a couple of nice optimizations can be done.

1) Start the inner entity loop at the current position of the outer loop + 1. In C++:

for(int a = 0; a < entities.size()-1; ++a)
    for(int b = a+1; b < entities.size(); ++b)
    {
        if( collision(entities[a], entities[b])
        {
            ....

2) If you keep a pointer to the last entity you collided with in each entity, for some collision_types you can ignore collisions with the same entity in a subsequent loop.

\$\endgroup\$

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.