Handling interaction/collision response between multiple "GameObjects" nicely.

Started by
8 comments, last by Nicholas Kong 10 years, 10 months ago

This is one of the hardest part of game-development according to my brain apparently, I have a hard time figuring out how to handle interaction between multiple objects that are derived from the same base-class.

Let me try to explain it. Lets say I have a few objects that all derives from the parent-class "GameObject":

  • Bullet
  • Player
  • Enemies
  • Power-Ups
  • Sword Slash Bounding-box
  • Tiles - such as platforms ect.

Here we have a lot of game objects, that shares the common attributes and functions which are stored inside an vector<GameObject*> which contains all the objects present on the map.

So far so good! But here is when my brain just implodes, trying to determine what interacts with what without looping EVERY object and dynamic-casting everything!

Lets assume I have some magical query function that can fetch an array of nearby objects from any arbitrary object!

What I do at the moment is something along the lines:

GameObject has two virtual methods called getType() and getSubType() which returns a string.
When queering close by objects, I iterate through the vector checking if anyone is colliding ( or whatever triggers the interaction ) and if they are I check what type they are, to determine if they should react to the colliding object.

I often put the interaction code inside of the object - i,e Bullets interacts with either Player or Enemy ( depending on the subtype ), Power-Ups interact with the Player and so on:

Example:


// Inside of Player-class
void update( float dt ) {
    /* Code */
    vector<GameObject*> v = mWorld.fetchObjects(this->x,this-y,50);
    for( GameObjects* o : v ) {
        if(o->collide(this)) {
            o->interactWith(this); // Object "o" will check "this"->getType() and determine what it will do.
        }
    }
}

Though I am a bit afraid I might do some unecessary already done collision checks+interactions - but shouldn't be a problem as long as I define what object interacts with what! I.E Bullet checks for Enemy-collisions but Enemies don't check for Bullets ( a bit weird isn't it? ).

The problems I feel with this approach is that:
1) It's not clear of what object should check for what collision - Enemy vs Bullets or Bullets vs Enemies?
2) Not flexible when more and more object-types are introduced.


I have tried searching for clean, simple ( low on complexity and code-base ) 2D projects to see how they handle all the objects interaction - especially when they are "anonymous" as in they are stored in a vector<GameObject*>.

There must be a better way ( without resorting to Component systems or a shit ton of dynamic-casts ) to deal with interacting with different types of objects!

Hopefully someone will spread some light on this topic because my searches have failed me.

Kind regards,
Moonkis

Advertisement

Have you thought of using a physics engine? It could handle all the 'collision' part for you and give you useful feedback. A few good physics engines are Bullet, Physx, and my favorite.. Newton.

Hope this helps!

Edit: If your game is 2d then a good physics engine to use would be Box2D.


The problems I feel with this approach is that:
1) It's not clear of what object should check for what collision - Enemy vs Bullets or Bullets vs Enemies?
2) Not flexible when more and more object-types are introduced.

...

There must be a better way ( without resorting to Component systems or a shit ton of dynamic-casts ) to deal with interacting with different types of objects!

If we want to make it super easy, I guess you could just do something like

struct GameObject {
    RigidBody *collision;
    ...
};

So it's not about GameObjects anymore, it's about stuff colliding, only one type. Pull out this pointer and then map those pointers to entities.

Personally I believe putting collision response immediately after collision detection is not very viable. You cannot put "game entity" information in the collision phase: it doesn't make sense. Provide it with the required subset of data and nothing more.

You might eventually try with base classes but in the end, it's never too early to start looking in the direction of how good physics is done, which is using a library. Otherwise, your code grows in a vacuum. Supporting libraries are there and you'll be required to use them. Think about it.

Previously "Krohm"

Hi,

in your situation duoble checking could be avoided checking two object ids or adresses , for example if(this->id>obj_to_check->id)check(), but even better to use some broadphase algoritm (if there is >=100 objects and collision checks are cpu eaters) or even simple bruterorce outside update, I mean more logical would be first to update all objects than check collision without dublicate checks....

//brute force

for(all objects)obj[]->update();

for(i=0;I<all objects)

for(k=i+1;k<all objects)

check_collision(obj,obj[k]);

next thing to avoid some unnessesary checkings you can use bit operations. for example every object can have two variables

int has_mask; //object property bits =MASK_SOLID | MASK_ENEMY_CLAN | ... //enemy ship

int accept_mask; //accepts collision with objects that has properties =MASK_SOLID | MASK_PLAYER_CLAN; //enemy bullet

//flags

MASK_ENEMY_CLAN=0000001

MASK_PLAYER_CLAN=0000010

...

if(obj1->has_mask & obj2->accept_mask || obj2->has_mask & obj1->accept_mask)do_collision(); //must be checked

so something similar aproach...

I wish it helps you...

I'm disappointed - I'm not interested in a Physic-lib ( I want to be able to do it and understand it myself ) nor is the actual collision detection the problem. It's about interaction!

I want to know how too handle interaction between a lot of different object-TYPES - seeing as they are stored as GameObject*
A bullet will for example interact with an Enemy and Player but not a Power-Up

Krohm

So it's not about GameObjects anymore, it's about stuff colliding, only one type. Pull out this pointer and then map those pointers to entities.

Personally I believe putting collision response immediately after collision detection is not very viable. You cannot put "game entity" information in the collision phase: it doesn't make sense. Provide it with the required subset of data and nothing more.

Could you please elaborate?

I generally do collision detection and response as part of each game object's update, rather than a separate pass done at the end.

For example, a bullet, in its update, would query the collision world with a set of flags like Serumas describes, and its current position and velocity. If it doesn't find anything, then add velocity to position. If it does find something, inform the thing that it's been shot, and flag the bullet dead (or delete the bullet immediately, if that's safe to do from inside its own update). Informing the thing would most likely be done by a virtual function to avoid having to check what type it is. Even if your base entity class doesn't have a "takeDamage" function, you know from the collision flags you used that it's safe to static cast to the base class of things that can take damage. Or better yet, implement an assert_cast, which compiles to static_cast in optimized builds, or dynamic_cast and assert != null in debug builds.

A player would query the collision world with a different set of flags. Actually two separate traces. One for motion, where you modify your velocity to slide against any objects returned. Second trace for non-motion collision, including powerups, and possibly enemies if they cause damage on contact but don't block your movement, such as in a Mario style platformer. In this case, you'd have to check what type you hit. If enemy, then damage yourself (possibly needing to cast the collidee pointer to an enemy, to find out exactly what type it is). If powerup, then cast to powerup pointer and see what kind it is, and handle appropriately. Or, you could not have the player check for enemies at all, but rather in the enemy's update, check for players, and call takeDamage on them.

If the player has a sword slash attack, and is currently attacking, then do a third trace with the slash collision box, and flags set to return things that can be cut. Anything that's returned, call takeDamage on it like the bullet did.

Moving platforms may not check collision at all in their own update. In a Mario style game, platforms generally just follow their mvoement path, going through anything that gets in their way. IME, it's easiest if you make sure all platforms update their position before the player. That way the player is always seeing the platform's new position, and can take that into account when moving (otherwise you can end up with the player lagging one frame behind the platform they're riding on). The only tricky bit is a platform moving upward while the player is falling. The platform can go from being below the player but the player still in the air, to the platform being above the player's feet, without the player ever landing on it. One option is to have the player check the platform's previous position and new position, to see if the platform crossed the player's feet in its last update.

First of all if you know you have to know what type each gameobject is... why manage them as just one type? I feel it makes things overly complicated especially when the majority of those objects are very different from one another.

I'd use the advice already given and have your objects store a collision object that can be registered with your physics system. Collision shouldn't care about anything but the physical part of your object not its type. Your collisionnobject can store the info on what objects it collided with. Then later you can update each object and apply the collision rezponse based on the stored collisionninformation.

As for special cases such as a bullet hitting the enemy. When you iterate over your enemies you know they will respond to being hit by bullets so would check the objects that it collided with if they are bullets.

In my current project I handle such responses by including a flag for friendly or enemy... and a damage value. If an object such as the player collides with another object i first check if the objects are on the same side or jot. I.e. are they both friendly. If so I just leave it to the physics to respond. If not I check if either have a damage value above 0 and apply that to the given object.

Interactable objects all derive from a base object to facilitate this but are stored seperately for easier and faster management. I.e. I know when I'm updating a bullet cause I'm updating the bullet container. No need to check types.
[ dev journal ]
[ current projects' videos ]
[ Zolo Project ]
I'm not mean, I just like to get to the point.


The problems I feel with this approach is that:
1) It's not clear of what object should check for what collision - Enemy vs Bullets or Bullets vs Enemies?
2) Not flexible when more and more object-types are introduced.

If the collision handling code between two objects doesn't really belong in either object, you might consider putting it in a separate helper function. That way, Enemies don't need to know about Bullets, and Bullets don't need to know about Enemies.

The helper function could be run as part of your update cycle, and would enumerate the Enemies and check against each Bullet. Then it could, just as an example, check the Power of the bullet, compare it against the Armor of the enemy, call a TakeDamage() method on Enemy with the resulting damage it calculated, and then deactivate the Bullet. Given that the function exists outside of Bullet/Enemy, it makes more sense that it could take advantage of some kind of spatial optimizations (which require a larger knowledge of the game world) for efficient collision detection. (Of course, you could also integrate a 3rd party physics library to handle the actual collision detection).

As more types are added, of course you need more code to handle these things - but at least, for instance, you wouldn't need to make changes to Enemy if you decided to introduce a Laser object type. The code could exist elsewhere and still call the TakeDamage() method.

You can make the physics engine more generic by adding a messaging or event system of sorts. A bullet could create a physics body and register a message listener for when a collision is detected. It can then do the bullet specific logic in the listener.

You should also add some flexibility to the physics engine itself. For example, collision groups (a bitmask, objects only collide if they share a bit in their masks), noncolliding objects (that still notify any collision listeners), custom collision responses (the bullet could ricochet for example, overriding the default collision response logic)

o3o

You can use an interface. You can call it Collidable.

Establish your collision code in the Collidable interface.

This makes it easier for your collidable objects.

Even if you decide to change your mind that this object not being collidable in the future, you can just erase the collidable interface from that class.

You do have to type cast when you do this. I am not sure why you would want to do it without casting because the language needs to know what type of object you are talking about which in this case is Collidable.

It is not weird. You do not want to perform back-to-back collision or check the same collision from a different perspective even though the initial thought may be so. You can use the object that is likely to be alive the whole game which is the bullet to check collision on the monsters.

You can even optimize the collision so that the bullet does not check collision until it has reached the bounding rectangle of the enemy and then perform the following intersection check!

This topic is closed to new replies.

Advertisement