Custom collision response

Started by
7 comments, last by bzroom 15 years, 10 months ago
How do you guys handle special events on collisions? I just do some basic kinematics stuff on everything by default, but I have no way to say things like "if this is a bullet, explode and cause damage to everything around" I can think of a couple solutions but I figured I'd ask before I went reinventing the wheel.
[size=2]
Advertisement
I once created a system where logic entities could register collision shapes with a collision system. This system would take care of standard collision handling, but logic entities could request to be notified upon collisions, or they could request different collision handling (I'm a ghost, notify me about collisions but don't push me out of other shapes). Worked well enough for the 3D adventure game we were working on.
Create-ivity - a game development blog Mouseover for more information.
Look into a message or event system. Whenever your objects collide, send both objects a message saying they collided with something (and what it is). Than, the objects can interpret the messages and act accordingly (in your case, explode).
Comrade, Listen! The Glorious Commonwealth's first Airship has been compromised! Who is the saboteur? Who can be saved? Uncover what the passengers are hiding and write the grisly conclusion of its final hours in an open-ended, player-driven adventure. Dziekujemy! -- Karaski: What Goes Up...
I like to setup two callbacks on my physics body. PreCollision, PostCollision. In the PreCollision callback, the collision is only "predicted" to happen, like via an AABB overlap or something. The user can choose to reject this collision (or handle it appropriately). In the PostCollision, depending on the API, the user will not likely be able to reject the collision, only handle it. However, in PostCollision, the exact contact point will be know (and the collision is confirmed).

Users can add a simple low level engine callback to the physics body for these two situation. The callbacks call to game level, and the game programmers can do what ever they want.

As far as explosions, that is another method of the physics scene. It should take an epicenter, blast radius, impulse strength, and a impulse taper value (describing the fall off). I like to queue these up before I actually detonate them. Primarily because if one explosion was setting off multiple other explosions, and you didnt wait until the next frame, the frame time would be rediculous. So only handle 1 generation of explosions per frame (or some other max number).

When the explosion gets handled, query near by physics bodies. Apply an impulse, call their collision callback but pass an "I'm an explosion" flag with the collision callback data. Additionaly I add callbacks to the explosion itself. For each physics body affected by the blast, I call back to the user and pass the body and the blast intensity. When the explosion is over, I make a final "completed" callback. So the user can unregister anything specific to that explosion. Did I just give away all my secrets?
This is one of the more complicated game engine issues you don't really consider at first. Pretty much at the point where you detect a collision, you must either directly tell objects or send some form of message. Additionally there is stuff like sound effects and particle effects and destroying objects.

Personally, I keep it simple. Since the Collision Routine is necessarily aware of all involved collidable game objects (if not, how can it collide?) I have it directly tell objects "you have been damaged" or "you have been destroyed" and tell relevant Managers to produce sounds, particle effects, or whatever.

Setup is as follows:

CollisionManager: all collision detection routines here. Is aware of all game objects, the SpawnManager, and the SoundManager.

All game objects have a TakeDamage(int damage) routine. They will reduce their health and die if necessary, with all related side effects.

SoundManager: plays sounds through simple functions such as "PlayBulletImpactSound()". Alternately, your bullet itself could have an Impact sound reference. I like keeping sound separate though.

SpawnManager: functions for dynamically spawning/despawning objects in the game. For example, when a projectile hits something, its spawns a ProjectileImpact particle effect. So the SpawnManager has a SpawnProjectileImpact(vector3 position) function.

So, putting it all together, pseudo code for the Projectile to Player collsion routine looks something like:

void collideProjectileToPlayer(Projectile proj, Player player){   // detect collision ...   // collision has occured   if(collision)   {      player.TakeDamage(proj.damage);      SoundManager.PlayImpactSound();      SpawnManager.SpawnImpactEffect(proj.position);      SpawnManager.DeSpawn(proj);   }}


Probably not the ultimate in SW engineering, but it straightforward, fairly OO, and readable.
I'm not using inheritance so I can't use double dispatch or such to get the runtime type of objects in order to call things like collideProjectileToPlayer.

My first attempt at a solution is (was) to give every collideable a pointer to a functor which would be called whenever it was involved in a collision.

Collideable::Collide(Entity other){  if(collision(other))  {    CollisionFunc(other);    other.CollisionFunc(this);  }}


This works decently for many cases but it's often unclear exactly how much of the collision each entity should be responsible for. For example, the CollisionFunc for a bullet should probably be to spawn the explosion and do damage to the target, but should it apply some force to the target too? Probably, since the bullet knows about the force of the explosion and the target doesn't, but still, it's not obvious.

The other problem was when I tried to implement some basic conservation of momentum. The first CollisionFunc set the velocity of this to the inverse of other, but then the original velocity of this was lost when other tried to do the same. I might be able to get around this partially by creating copies to send to these two functions, but I figured I'd ask before I spent too much more time on it.
[size=2]
I'm not sure if you're doing your own physics or not, but that is kind of a sepperate issue (anything momentum related). So you have your real physics layer, and your physics management layer.

The physics management is what informs the game that there has been or will be a collision between two object. The real physics layer doesn't care, it just does it's job, which is collide and integrate physical bodies.

So if you're writting your own complete physics library, make sure you seperate these layers.


A an example of a game level Bullet Object.
class Bullet : public PhysicsObject{public: Bullet() {   PhysicsObject::SetQuality( BULLET );   PhysicsObject::SetOnImpactCallback( &CollisionCallback, (void*)this /*owner*/ ); }   void Incinerate( const Float3 location ) {   m_FireEffect.Play(location); } static void CollisionCallback( CollisionData &data ) {  Bullet *bullet = static_cast<Bullet*>(data.owner);  //set off effects and stuff  bullet->Incinerate(data.contactPoint);   //add the force  data.CollidedWith.AddImpulse( bullet->velocity * bullet->mass, data.contactPoint ); }private:...};


The public properties of the physical body are double buffered (or copied), so when you AddImpulse, it's not going to change the targets velocity until the next physics step. BTW

I came across this earlier today, scroll to 1m 44s for explosions.
http://video.google.com/videoplay?docid=-4206956356177547375&hl=en

[Edited by - bzroom on May 29, 2008 3:08:42 PM]
Quote:Original post by bzroom
I'm not sure if you're doing your own physics or not, but that is kind of a sepperate issue (anything momentum related). So you have your real physics layer, and your physics management layer.

The physics management is what informs the game that there has been or will be a collision between two object. The real physics layer doesn't care, it just does it's job, which is collide and integrate physical bodies.

So if you're writting your own complete physics library, make sure you seperate these layers.


A an example of a game level Bullet Object.
(snip)


I came across this earlier today, scroll to 1m 44s for explosions.
http://video.google.com/videoplay?docid=-4206956356177547375&hl=en


Very true. The cases I didn't want to use normal physics (ie. bullet on player) were only because my system was really simplistic (placeholder until I can check out Havok* =)). If I were to take into account mass then I wouldn't have the player bouncing off bullets anyways.

Neat video too.

* It's almost the end of may, where is my free Havok =(
[size=2]
Thats true, bad example. People typically don't use real physics for bullets. It was just a simple example. Let's just imagine that I had called it Rocket instead of Bullet :) Add a PerStep callback and add a rocket booster force to complete the package.

Although, I think that the PhysicsObject should be able to provide fake bullet physics, because idealy it would be a real physics object. So being able to just pretend that, and have it fake it under the hood, that would be really handy.

I feel you on the Havok, did they tease us?

[Edited by - bzroom on May 29, 2008 4:44:25 PM]

This topic is closed to new replies.

Advertisement