Sign in to follow this  
macmoy

How To: Collision Detection Management

Recommended Posts

Hi there. Im making a game using c++ and dx9. its a spaceship 2d game.i have classes like: enemyship heroship particle - for spaceship engine(fire effect) bullet .. .. etc. where will i put the detection for collision? should i make another class? or put it inside enemyship::update()? or heroship::update()? or bullet::update()? please, help me manage collision detection for games. I really dont know how. i searched google for "game collision management" but had no luck. thanks for any help..

Share this post


Link to post
Share on other sites
Here's the short answer. Don't put the collision detection and response code in any of the classes you mentioned; instead put it in a module (class, function, or whatever) that 'knows' about all of the objects in your game (or at least the ones that can interact with each other). This module can then perform the intersection tests and take the appropriate action (such as removing an entity from the game) when an intersection is detected.

The module could be a 'game' class, a 'main loop' function, a callback of some sort - it's really up to you.

Share this post


Link to post
Share on other sites
im slightly confused.

how can i check (i.e. the 50 bullets(2d sprite/texture) from bullet class) when it is private:? use a function that returns it? or is there any approach(better)?

Share this post


Link to post
Share on other sites
Give the entity classes public member functions that can be used to get at any information useful for collision detection. Chances are you don't need the actual sprite/texture for collision detection, just the transformation and dimensions, you could have functions that return these individually, or a single/few coarse functions that return this information all bundled up specifically for the collision module.

Share this post


Link to post
Share on other sites
ok, thanks, its clear to me now.

can you give the class definition? (collision class)

what functions should i include inside that class?

Share this post


Link to post
Share on other sites
Maybe like that:



class Collision {
public:
Collision() {}
~Collision() {}

bool Collided(Object * obj1, Object * obj2);

};





Where Objects are enemyship, heroship, bullet, particle, asteroid, etc. etc.

You have to use it with every class at once:


bool Collided(enemyship * obj1, heroship * obj2);
bool Collided(enemyship * obj1, bullet * obj2);
bool Collided(heroship * obj1, bullet * obj2);



or you can add a base class Object and derived classes enemyship, heroship, bullet, etc.

Kasya

Share this post


Link to post
Share on other sites
the visitor pattern is fine, but imo it's produces too many dependencies, especially if you expand your class types.

Also, I'd recommend you separate your entities (PlayerShip, EnemyShip, PlayerBullet, EnemyBullet, Terrain, ....), from actual collision objects.

a PlayerBullet 'has a' collision object, rather than a PlayerBullet 'is a' collision object. Collision for player bullets could be anything from say, a single point moving about, to a rectangle, to a small disk.

so I'd have my collision objects as such


enum
{
COLL_OBJECT_TYPE_DISK,
COLL_OBJECT_TYPE_RECTANGLE,
COLL_OBJECT_TYPE_PARTICLE,
COLL_OBJECT_TYPE_SEGMENT,
COLL_OBJECT_TYPE_COUNT,
};

class CollObject
{
public:
CollObject(class Entity* owner, int type)
: m_type(type)
, m_owner(owner)
{}
virtual ~CollObject(){}

const int m_type;
class Entity* m_owner;
};

class CollRectangle: public CollObject
{
public:
CollRectangle(class Entity* owner, const Vector& centre, float width, float height)
: CollObject(owner, COLL_OBJECT_TYPE_RECTANGLE)
, m_centre(centre)
, m_width(width)
, m_height(height)
{}
Vector m_centre;
float m_width;
float m_height;
};

class CollDisk: public CollObject
{
public:
CollDisk(class Entity* owner, const Vector& centre, float radius)
: CollObject(owner, COLL_OBJECT_TYPE_DISK)
, m_centre(centre)
, m_radius(radius)
{}
Vector m_centre;
float m_radius;
};

class CollParticle: public CollObject
{
public:
CollParticle(class Entity* owner, const Vector& position, const Vector& velocity)
: CollObject(owner, COLL_OBJECT_TYPE_PARTICLE)
, m_position(position)
, m_velocity(velocity)
{}
Vector m_position;
Vector m_velocity;
};

class CollSegment: public CollObject
{
public:
CollSegment(class Entity* owner, const Vector& start, const Vector& end)
: CollObject(owner, COLL_OBJECT_TYPE_SEGMENT)
, m_start(start)
, m_end(end)
{}
Vector m_start;
Vector m_end;
};



and my entites as such


enum
{
ENTITY_TYPE_MY_SHIP,
ENTITY_TYPE_MY_BULLET,
ENTITY_TYPE_ENEMY_SHIP,
ENTITY_TYPE_ENEMY_BULLET,
ENTITY_TYPE_COUNT,
};

class Entity
{
public:
Entity(int type)
: m_type(type)
, m_collObject(NULL)
{}

virtual ~Entity()
{
if(m_collObject)
delete m_collObject;
}

const int m_type;
CollObject* m_collObject;
};

class MyShip: public Entity
{
MyShip(const Vector& position)
: Entity(ENTITY_TYPE_MY_SHIP)
{
m_collObject = new CollRectangle(this, position, 32, 64);
}
};

class EnemyShip: public Entity
{
EnemyShip(const Vector& position)
: Entity(ENTITY_TYPE_ENEMY_SHIP)
{
// use a disk
m_collObject = new CollDisk(this, position, 32);

// or a rectangle
//m_collObject = new CollRectangle(this, position, 32);
}
};

class MyBullet: public Entity
{
MyBullet(const Vector& position, const Vector& velocity)
: Entity(ENTITY_TYPE_MY_BULLET)
{
m_collObject = new CollParticle(this, position, velocity);
}
};

class EnemyBullet: public Entity
{
EnemyBullet(const Vector& position)
: Entity(ENTITY_TYPE_ENEMY_BULLET)
{
m_collObject = new CollDisk(this, position, 32);
}
};



now, as far as testing for collisions, instead of tying the collision objects together via a visitor interface, I'd probably use a function pointer table, that will call the appropriate function depending on the type of objects. You could also use functors() and such, but it can get a bit mad. That would be wrapped up into a module that would provide functionality to call collision routines and process collisions depending on the type of entites you test against.



struct CollisionInfo
{
Vector m_normal;
Vector m_contactPoints[2];
CollObject* m_collObjects;
};

class CollisionManager
{
public:
virtual bool canCollide(const class Entity* a, const class Entity* b) const
{
// collider table
static bool s_table[ENTITY_TYPE_COUNT][ENTITY_TYPE_COUNT] =
{
// myship, mybullet, enemyship, enemybullet
{ false, false, true , true, } , // myship
{ false, false, true , false, } , // mybullet
{ true, true, false , false, } , // enemyship
{ true, false, false , false, } , // enemybullet
};
return s_table[a->m_type][b->m_type];
}

virtual bool collisionResponse(CollisionInfo& info)
{
// make entities bounce, explode or whatever when colliding.
}

virtual bool collisionDetection(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
typedef bool (*CollideFunc)(const CollObject* a, const CollObject* b, CollisionInfo& info);

CollideFunc s_table[COLL_OBJECT_TYPE_COUNT][COLL_OBJECT_TYPE_COUNT] =
{
{ rectangleCollideRectangle, rectangleCollideDisk, rectangleCollideParticle, rectangleCollideSegment, },
{ NULL, diskCollideDisk, diskCollideParticle, diskCollideSegment, },
{ NULL, NULL, particleCollideParticle, particleCollideSegment, },
{ NULL, NULL, NULL, segmentCollideSegment, },
};

// rejected collision, to avoid doing epxensive test.
if(!canCollide(a->m_owner, b->m_owner))
return false;

// swap objects to call the correct routine
if(a->m_type > b->m_type)
return collisionDetection(b, a, info);

// call the function from the function table
CollideFunc testCollision = s_table[a->m_type][b->m_type];

return testCollision(a, b, info);
}

static bool rectangleCollideRectangle(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do rectangle-rectangle collision routine.
}
static bool rectangleCollideDisk(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do rectangle-disk collision routine.
}
static bool rectangleCollideParticle(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do rectangle-particle collision routine.
}
static bool rectangleCollideSegment(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do rectangle-segment collision routine.
}
static bool diskCollideDisk(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do disk-disk collision routine.
}
static bool diskCollideParticle(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do disk-particle collision routine.
}
static bool diskCollideSegment(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do disk-segment collision routine.
}
static bool particleCollideSegment(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do particle-segment collision routine.
}
static bool particleCollideParticle(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do particle-particle collision routine.
}
static bool segmentCollideSegment(const CollObject* a, const CollObject* b, CollisionInfo& info)
{
// do particle-particle collision routine.
}
};




Share this post


Link to post
Share on other sites
so, in the case of a collision table, as you start introducing more object types and more complex interactions, you just end up adding more entries in the tables, and if you want to add another collision object type (say, a polygon), you add extra collision routines in the collision table as well.

You would also ideally add collision response tables as well, as the response to different events (ship-ship collision, or bullet-ship collisions) would produce different outcomes.

At the end of the day, a collision module (the C CollisionManager class) would be what I'd do as well, to move the dependencies away from the objects and give more flexibility.

The implementation then is up to you (function pointer table, hash map functors, a big nested switch-case statement, ect...) but the interface should be quite similar. A collision detection routine, and a collision response routine.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this