Interaction between Colliding Objects

Started by
15 comments, last by BeerNutts 12 years, 11 months ago
What's a good way of managing a collision system like in a Top-Down Shooter that involves the collision of Projectiles and other kinds of Entity such as enemies and players, where clearly there's at least an apparent difference in how collisions work depending on what kind of Entities are involved?

For instance, it's easy enough when a Projectile hits a wall; just despawn the Projectile or whatever, but what about the extra complexity of player characters, enemies etc.interacting with each other, Projectiles and the map?

Where should the responsibilities lie and how should it be structured?

Take a simple example of:
A bullet is fired from a gun and collides with an enemy.
We want the following results:
- The bullet should despawn (perhaps explode if it was a rocket or something but that's another story).
- The enemy should take damage dependent on the stats of the bullet, and perhaps be knocked back a certain distance dependent on the bullet's stats.
- Perhaps in some cases the enemy might have an effect on the Projectile itself? Just speculating here, but some kind of... shield that deflects bullets for example.

It's a simple enough example but raises a lot of questions:
- Should the Projectile or Enemy interact directly with the other? Or should a 3rd party manage the collision?
- If an Enemy hits a Player (probably both entities of the same subclass), how should that be handled? With a different function or 1 common generic system for all Entity collisions? (Assuming Projectile inherits from Entity also).
- Should Entities have some kind of handleCollision() functions? Or should the object managing collisions just call functions of the Entities to produce the desired effects? inflictDmg(), knockBack() for example.
- In a more complicated example, what if you want a Projectile to confer some kind of status effect on an Entity? Or otherwise alter it beyond simple damage? There must be a reasonable way to allow such things without messing around outside the Projectile too much. I suppose call some function of the Projectile which then calls a function of the Entity. But that leaves room for various possible implementations...

What's a good starting point for something like this? I'm finding it hard to come up with something that seems relatively flexible and not counter-intuitive or messy.A high-level view of the rough idea would be good, or anything more detailed than that.

Given my ideas for Projectiles causing knockback as well as damage and possibly various effects... I imagine a Projectile should directly interact with something it hits, but then should the Entity do the same with the Projectile? And what if a Projectile hits an Entity, but then can hit another Projectile too? A Projectile would perhaps have some different members to a Creature Entity, so should there be separate functions for these different collisions? Or would some kind of simple message system be better? In which case, a Creature might receive "INFLICT_POISON" and do something, but a Projectile could ignore it.

Any ideas?
Advertisement
You may be over thinking things...take it a step at a time. Get one thing working and then add different layers as needed. Keep it really simple, and it will then be simple to expand on what you have.
GregMichael is right. Anyway I think I can answer some of your questions.

For instance, it's easy enough when a Projectile hits a wall; just despawn the Projectile or whatever, but what about the extra complexity of player characters, enemies etc.interacting with each other, Projectiles and the map?[/quote]


It all depends on how far you want to go with details but you should try to keep it simple. To detect collisions you can just wrap each entity with a 'box' and then check which boxes are overlapped - by 'box' I mean a square, a rectangle, a circle etc.. And if you want to detail the thing a little bit more you can have several boxes associated with the same object. A simple example, an human with a gun, you can divide it into a rectangle to the gun and a square to the human, and consider both boxes as being an enemy.

- Should the Projectile or Enemy interact directly with the other? Or should a 3rd party manage the collision?[/quote]


Personally I like to keep things organized like this: (example created in a second so..smile.gif)

hit = bullet.detectCollision();
if(hit == true){
enemy.loseHp(bullet.getDamage());
}

This example is very simple but I think you can get an idea.


just despawn the Projectile or whatever[/quote]


You have to be careful when destroying an object. You can't destroy it before doing all the calculations where it is needed - like destroying a bullet right after checking that it collided and then try to calculate the damage it does using object variables like bullet.damage (hint: only destroy objects after all calculations or use some static variables).


I think you should start by trying to check a collision between circles, squares etc., and then move to more complex stuff.

Hope it helps

It all depends on how far you want to go with details but you should try to keep it simple. To detect collisions you can just wrap each entity with a 'box' and then check which boxes are overlapped - by 'box' I mean a square, a rectangle, a circle etc.. And if you want to detail the thing a little bit more you can have several boxes associated with the same object. A simple example, an human with a gun, you can divide it into a rectangle to the gun and a square to the human, and consider both boxes as being an enemy.


No I already have the actual collision detection code working, I just need to figure out how to organize it properly when it comes to object interaction and taking the various actions that must be taken when a collision is detected, without making an complicated mess.
Your collision events are probably already tagged by object types (bullet - spaceship? Then mark the bullet for deletion, spawn an explosion at the collision location, and damage the spaceship according to the damage field of the bullet) and you can further filter them as you see fit (if the bullet is flagged as "material", i.e. not "particle beam", and "big", apply its momentum as a deflection of the ship's velocity). Every type of collision is independent, and you can factor what they have in common into separate behaviours (the same rather involved bouncing computation can be reused for big material bullet vs spaceship, spaceship vs spaceship, spaceship vs debris, and so on). You can also try moving anything unnecessary, like checking whether a spaceship is dead, out of collision handling and into a separate pass.

Omae Wa Mou Shindeiru

He's asking where the collision should be handled. For most situations, this should be handled in both the hitter and the hitee.

For example, a bullet hits an enemy. Let's assume you loop through all the enemies on the screen, checking if they've hit something. Let's say they hit a bullet. IMO, since both the enemy and the bullet could do different things based on the situation, you should handle it in both places. ie:

if (Collide(EnemyToCheck, BulletToCheck))
{
// let enemy do whats required for this type of bullet (be it take damage, a change in velocity, nothing (if shielded for example), etc.
EnemyToCheck->HandleCollision(BulletToCheck);

// now let bullet do what's required when hitting this enemy. Normally, just despawn, but maybe explode, maybe change of velocity/direction, etc.)
BulletToCheck->HandleCollision(EnemyToCheck);
}

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

I would suggest using an event system;

Define an event class, event listener class and an event manager class.
Add event listeners to classes that should respond to events, and have one instance of the event manager class that'll be global to the game.
The event manager uses containers such as a hash table or a STL map to link the listeners to the event-types. As soon as an event has occured, by calling TriggerEvent("Event_ShootGun"); or something similar, the manager checks to see what listeners are subscribed to this event type and calls all the liseners HandleEvent(); functions that will process the event each on their own way.

For more information how to implement I would recommend reading Game Coding Complete, or otherwise search google for implementations.

For example, a bullet hits an enemy. Let's assume you loop through all the enemies on the screen, checking if they've hit something. Let's say they hit a bullet. IMO, since both the enemy and the bullet could do different things based on the situation, you should handle it in both places. ie:


Yes... that was a way that did look promising and logical. I'll have each entity deal with its own effects then. Seems good.

Given though, that all colliding objects will inherit from Entity, should the functions be separate for each type, e.g.: enemy->collision( Projectile p ), enemy->collision( Creature c ) or would it be practical to have a single function like enemy->collision( Entity e )? Maybe there should be few enough separate classes that separate functions shouldn't be a real nuisance or issue. I'll probably do it that way unless I can think of something good that makes sense.

An event system might be good... but it's quite a shift from what I've been doing so far, don't think that's a real option with this project at this stage. Deadlines etc.
Have looked at/experimented with event listeners in the past though and it was quite interesting, think I'd need more research before implementing it practically still.

One more question:
- A Projectile hits a wall and should be despawned. How should I accomplish that? Keeping in mind, right now each Projectile has a separate member object which determines its behaviour so it's that Behaviour object which will need to signal a despawn to occur.
I'm thinking, just add the parent Projectile to some kind of destroyedEntities list or w/e and then iterate through that every frame and deal with them.
However, all Projectiles are currently on a list (std::map actually) of Projectiles which is iterated through to update them etc.
How then would I move a Projectile from one list to another?

OR, just some other way to do the same thing, which is to cause the deletion of the current object's parent object.


Yes... that was a way that did look promising and logical. I'll have each entity deal with its own effects then. Seems good.

Given though, that all colliding objects will inherit from Entity, should the functions be separate for each type, e.g.: enemy->collision( Projectile p ), enemy->collision( Creature c ) or would it be practical to have a single function like enemy->collision( Entity e )? Maybe there should be few enough separate classes that separate functions shouldn't be a real nuisance or issue. I'll probably do it that way unless I can think of something good that makes sense.




That's for you to decide. You could have a high-level Projectile::HandleCollision(Entity EntityCollidedWith) which handles all cases where the bullet just despawns (like for the simple bullet).

But, for your BouncyBullet (which bounces off walls, but hurts enemies), you would need a special BouncyBullet::HandleCollision(WallType WallCollidedWith), to handle changing direction/velocity when it hits a wall. Otherwise, it can inherit the parent's HandleCollision()



One more question:
- A Projectile hits a wall and should be despawned. How should I accomplish that? Keeping in mind, right now each Projectile has a separate member object which determines its behaviour so it's that Behaviour object which will need to signal a despawn to occur.
I'm thinking, just add the parent Projectile to some kind of destroyedEntities list or w/e and then iterate through that every frame and deal with them.
However, all Projectiles are currently on a list (std::map actually) of Projectiles which is iterated through to update them etc.
How then would I move a Projectile from one list to another?

OR, just some other way to do the same thing, which is to cause the deletion of the current object's parent object.
[/quote]


I would remove the despawns entity from the Active List or Projectiles list in your example) to a deactive list (what you called destroyedEntities). Once you have looped through all the entities to check, you can then delete the entities in the deactive list.

That's how I'd do it, but, there are tons of "right" way to do this sort of thing. GL.


My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)


I would remove the despawns entity from the Active List or Projectiles list in your example) to a deactive list (what you called destroyedEntities). Once you have looped through all the entities to check, you can then delete the entities in the deactive list.

That's how I'd do it, but, there are tons of "right" way to do this sort of thing. GL.


Cool, thanks for that.

One more thing:
My Projectiles are updated in a loop, so if a Projectile's update() function detects it should be despawned... I'm wondering if I can just remove it from the list then and there, and continue looping through without any problems? I see erase() doesn't invalidate iterators with std::list, so does that mean I can have something like:
[source]
for( all Projectiles in list )
{
currentProjectile->update();
}

Projectile::update()
{
if( collision )
{
remove from Projectile list;
add to inactive list;
}
}
[/source]

And the loop should continue normally? Sure looks like it.

EDIT: No... doesn't work...

Seems like I'll have to iterate through the active list to find every member of the inactive list for removal. Seems inefficient but I can't think of a better way.

This topic is closed to new replies.

Advertisement