Jump to content
  • Advertisement
Sign in to follow this  
Replicon

Collision handling (not detection)

This topic is 4578 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was wondering what clever and innovative solutions people out there have come up with for the problem of how to handle collisions as generically as possible. Note that I'm NOT asking how to do collision-detection. Rather, once your code says "hey, these two game objects have collided", how do you typically handle it in a nice and generic/flexible/scalable fashion? This isn't as trivial as it may seem. For one thing, different object types have to have different behaviours when combined. If a character gets hit by a shotgun blast, he'll bleed some and fall over dead. If a character is hit by rocket, he explodes all over the place. If a bullet hits a bullet... well, in most games, those age ignored/do nothing, fine... If a character hits another character (walks into him), it's just a soft collision that prevents one from just passing through the other somehow... if a character gets hit by a car, he gets flattened... if a car gets hit by a car, there's a nice crash sequence......... As you can see, this problem can get quite hairy, and a silly enumeration of pairs of object types that can collide, and the effect it has, just doesn't sit right with me (but I guess in some cases, it's necessary). In a very simple game (e.g. Gradius-style space scroller), one can come up with some restrictions. For instance, every sprite can have only ONE death sequence (explosion, let's say). Then, you can say EVERY game object has a certain "energy level" (an integer). When two objects collide, you take the min of their energy levels and subtract them from both. Any of the two (at least one of them) that are at zero are now destroyed. This solves some problems nicely. If bullets have an energy level that is lower than anything else's, they will always be destroyed upon first contact. And if walls have more energy than anything else, they will never be destroyed. But what if I want to expand this model into something a little bit more flexible (but not necessarily SUPER-flexible)? What have you folks come up with for this type of problem? cheers!

Share this post


Link to post
Share on other sites
Advertisement
There's a really nice 2D graphics engine that handles these collisons that you discribed very well, it called Physical: http://physical.alecrivers.com/

But you'd have to understand a lot of simple calculus to handle both rotational forces and movement of the whole based on the collsion points of the objects, it's called rigid body.

Share this post


Link to post
Share on other sites
Oh sorry, let me clarify. I'm not talking about handling collisions from a physics perspective (though that's another interesting topic). Think old school 2D sprite games. This is more of a software design topic, sorry about the mixup (I guess I got carried away in the description hehe).

Share this post


Link to post
Share on other sites
I would have the collision code delegated to the game entities, and the 'collision manager' just asks the two objects involved to sort themselves out.

(Edit: Code changed to reflect some thought, see post below)
// pseudocode (C#)
enum CollisionType { Static, Physics, NoPhysics };
struct CollisionData {
CollisionType Type;
GameObject OtherObject;
}

class GameObject {
// All your basic entity code in here, including ...
virtual void Collide(CollisionData data){ }
CollisionType CollisionType;
}

class Bullet : GameObject {
int Damage;
Bullet(){ CollisionType = CollisionType.NoPhysics; }
override void Collide(CollisionData data){
if(data.OtherObject is IDamagable){
(data.OtherObject as IDamagable).Damage(Damage, this);
}
Game.RemoveEntity(this);
}
}

class Rocket : GameObject {
int Damage;
Bullet(){ CollisionType = CollisionType.NoPhysics; }
override void Collide(CollisionData data){
Game.RemoveEntity(this);
if(data.OtherObject is IDamagable){
(data.OtherObject as IDamagable).Damage(Damage, this);
}
Game.AddEntity(new Explosion(Position, Damage));
}
}

class DamagableCharacter : GameObject, IDamagable {
// Base class for player-controlled and enemy-controlled
// game characters who can take damage and die

// This doesn't need any custom collision at all any more!
// Damage is dealt by the enemy, motion is done by the
// collision manager and physics entity

void Damage(int amount, GameObject source){
health -= amount;
if(health <= 0){ ... // die horribly }
}
}



[Edited by - Bob Janova on June 7, 2006 1:59:57 PM]

Share this post


Link to post
Share on other sites
Right, that's my first iteration as well. While it makes logical sense to delegate that task to the game objects, a number of problems arise:

1) Every game object has an ugly switch branch in it.

2) Adding a new game object type involves updating said ugly switch branch in every other relevant game object type. This isn't THAT bad, since you can have a relatively small amount of types (sprites, bullets, solid structures), but it doesn't cover the cases where two objects of the same type may have a differing effect on another (different player death animation, for instance).

3) Suppose the game object manager detects a collision between obj1 and obj2 (remember, it doesn't know what these are). It may call obj1.collide(CollisionData(obj2)) or the converse (obj2.collide(...)). Or you could have it call both, and agree with yourself only to change the the object whose member function you're calling... But then, you have to worry about writing it up such that the order of execution of the two calls doesn't matter (one call changes the state of an object, so the other call cannot depend on any modified state).

What if the collision manager handled pairs of colliding game objects? You could have a default collision model (either pass-through/do nothing, or something like the default I described in my first post), and then branch only on the pairs you want to handle in a special way?

Share this post


Link to post
Share on other sites
Actually, I'm also working on this thing, and also have my problems with it ;)

My solution is also basing on the overridin idea, that BobJanova presented, but i use an affect() Method - that describes ONLY how THIS object is affecting the OTHER - because the affects hasn't to be reflexive - and mostly the aren't. On a collision(A,B) I check simple A.affect(B) and then B.affect(A). Of course - here you have to differ the object-type first. And I'm affraid - some kind of switching you can't avoid - you want somehow differ the responses, though. I haven't, however, hard-coded the responses - scripting it - brings the flexibility of adding new objects after the game is compiled. (yet, I don't know how fast the script will be running...). When you bring then a new object, you have only to describe in the object, how it will affect the enviroment and in the other objects, that collisions with it will be "special" (!= default), you add the affect(NEW_OBJECT) Method. In all other objects the new object will be affected by "default" case (for exaple bounce off if colliding with a spring).
Now, there is indeed the problem with the refexivity of the collision, so I've decided to add a "collisionDone" boolean in the object, that will be flipped, if the collision check will be done. I intentionally said "flipped", because if we would make them hardly "true", then we had to reset all the bools at the end of the check - and with "flipping" you can simply define one frame computing phase as "true" phase and the next as "false" and so on. So, when you have objectA collisions computed, then you flip his "collisionDone" state to the "phase-state", then, if there comes a objectB that already collided with objectA (and the responses were already computed), you will notice that through the "collisionDone" bool, and will simple skip the object. Should work - but I haven't implemented it yet.

My worry is now, how to integrate the collision events elegant to the "map-rules-checker"...

Share this post


Link to post
Share on other sites
This is what comes to mind, I don't know how good of a method it is though.
Using an "enum" for object types:

enum ENTITY_TYPE
{
ENTITY_NPC,
ENTITY_BULLET,
ENTITY_ROCKET
};

class IEntity
{
public:
// ...
virtual ENTITY_TYPE getEntityType() const = 0;
virtual void OnCollision(IEntity *other) = 0;
};

class CNPC : public IEntity
{
public:
virtual ENTITY_TYPE getEntityType() const { return ENTITY_NPC; }
virtual void OnCollision(IEntity *other)
{
switch(other->getEntityType())
{
case ENTITY_NPC:
stopMovement();
break;
case ENTITY_BULLET:
// .. etc.



Or without using an "enum":

class IEntity
{
public:
// ...
virtual void OnCollision(IEntity *other) = 0;
};

class CNPC : public IEntity
{
public:
virtual void OnCollision(IEntity *other)
{
if (dynamic_cast<CNPC*>(other))
stopMovement();
else if // .. etc.



Now you can just call the OnCollision for both objects involved in the collision.

Share this post


Link to post
Share on other sites
This thread contains some nice techniques for this (It's actually about collision detection, but the techniques should still be applicable).

Share this post


Link to post
Share on other sites
Quote:
Original post by Replicon
...

In a very simple game (e.g. Gradius-style space scroller), one can come up with some restrictions. For instance, every sprite can have only ONE death sequence (explosion, let's say). Then, you can say EVERY game object has a certain "energy level" (an integer). When two objects collide, you take the min of their energy levels and subtract them from both. Any of the two (at least one of them) that are at zero are now destroyed. This solves some problems nicely. If bullets have an energy level that is lower than anything else's, they will always be destroyed upon first contact. And if walls have more energy than anything else, they will never be destroyed.

...


That's actually a very good place to start. A field in 2D (for the 2D side-scroller) which contains this destructability information, as well as its colour data. If highly accurate reflection of bullets is wanted, the field could also contain surface normal data. Non-surface pixels would of course have a blank normal of 0, 0, 0 since they really don't ever collide with things.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!