Implementing collision detection [C++]
I'm just starting to write a collision manager class, and am undecided on whether to use inheritance or to just stick the information in a union in one class. I'm looking for the fastest way to implement collision of different types of object. Here's what I've got so far:
Inheritance:
A CCollisionObject base class, with a virtual function
virtual bool TestCollision(CCollisionObject * pOtherObject);
Which would for and register any collisions between the two objects. The positive side of this is that in the virtual call, the object will know what kind of collision object it is, but would still need to either query what type of object the second one was, or the CCollisionObject class would also need virtual functions to test for collisions between each type of object, so that the virtual TestCollision function could be called which would then call TestSpecificCollision on the second object passing itself, which is now a known derrived class of CCollisionObject.
All-in-one:
There is one CCollisionObject class, which has a union of different types of collision information and a Type member, which indicates which member of the union is the valid collision information. This way, in the TestCollision function, the types can be determined by two switch statements and then the correct collision test can be performed. It seems to me that this might be the fastest option, as no virtual calls must be performed, but is obviously not as "correct" as the inheritance approach, and would lead to one large TestCollision function should many different types of collision objects be needed.
So, any ideas? Ideally I'm looking for a fast and clean approach to this.
CCollisionObject tells me that it's a class (the initial C), which I already know, and that it's an object (the Object suffix), which I also already know. So, semantically, your class represents a collision, which doesn't correspond at all to its usage (why are you testing for the existence of a collision between two collisions?)
This leaves me with a conundrum as to what you actually intended your CCollisionObject to represent. The two possibilities are that they represent Hulls (a sphere, an AABB, an OBB), or that they represent Colliders (a rocket, a spaceship). These possibilities call for two distinct approaches.
However, the All-in-one approach I would never use, because it's a C idiom which will interact horribly with C++. Not only isn't it elegant at all (and it completely lacks type safety), but it will prevent from turning your collision information data into an object (since elements in an union are PODs). I would quite possibly use boost::variant to achieve the same effect instead, with a cleaner approach.
Ideally, I would approach Hull collision detection using multiple dispatch (search wikipedia for a clearer description of this approach). Multiple dispatch can be done either manually or using boost::variant, which uses a Visitor pattern to discriminate between types. Both ways are a violation of the open-closed principle, however, but I feel that this is not a problem because I don't believe Hulls should be extended through inheritance, but rather through CSG operations.
The Colliders side is somewhat more complicated. You don't want to use multiple dispatch (or anything that looks like it) because Colliders are specifically designed to be extended through inheritance. My approach of choice is to create a system as follows:
In this approach, I would then create a CollisionGroup<Rocket>, another CollisionGroup<Ship>, a function OnCollide(Rocket & r, Ship & s) to manage collisions between the two, and give them all to the constructor of a GroupCollisionManager<Rocket,Ship> owned by the game.
This leaves me with a conundrum as to what you actually intended your CCollisionObject to represent. The two possibilities are that they represent Hulls (a sphere, an AABB, an OBB), or that they represent Colliders (a rocket, a spaceship). These possibilities call for two distinct approaches.
However, the All-in-one approach I would never use, because it's a C idiom which will interact horribly with C++. Not only isn't it elegant at all (and it completely lacks type safety), but it will prevent from turning your collision information data into an object (since elements in an union are PODs). I would quite possibly use boost::variant to achieve the same effect instead, with a cleaner approach.
Ideally, I would approach Hull collision detection using multiple dispatch (search wikipedia for a clearer description of this approach). Multiple dispatch can be done either manually or using boost::variant, which uses a Visitor pattern to discriminate between types. Both ways are a violation of the open-closed principle, however, but I feel that this is not a problem because I don't believe Hulls should be extended through inheritance, but rather through CSG operations.
The Colliders side is somewhat more complicated. You don't want to use multiple dispatch (or anything that looks like it) because Colliders are specifically designed to be extended through inheritance. My approach of choice is to create a system as follows:
- ColliderHandle is a reference to a Collider, which doesn't know what type of Collider it references. Note that the Collider is not accessible or manipulable from the handle.
- CollisionGroup<T> contains objects of type T: its main purpose is to turn ColliderHandles into objects of type T and to provide the list of all handles to objects it contains, associated with their Hulls.
- CollisionDetector manipulates two sets of Hulls associated with ColliderHandles, and contains a functor which it calls when a collision is detected.
- GroupCollisionManager<A,B> detects collisions between a group of A objects and a group of B objects (each with their associated Hull provided by the user). This detection is performed by an internal CollisionDetector, which calls the GroupCollisionManager object through a functor. The GroupCollisionManager then calls an user provided function OnCollide(A & a, B & b) on the two objects which have collided—the types of the objects are known by design.
In this approach, I would then create a CollisionGroup<Rocket>, another CollisionGroup<Ship>, a function OnCollide(Rocket & r, Ship & s) to manage collisions between the two, and give them all to the constructor of a GroupCollisionManager<Rocket,Ship> owned by the game.
It's collision hulls that I'm implementing, so I'll probably change the class name to CCollisionHull. I think ideally i'd like to end up with classes like CAABBCollisionHull, CSphereCollisionHull etc. and to have them all derrived from the base class CCollisionHull. I was just wondering what the best way of having each type be able to test against all the other types would be. Each type would probably implement a TestCollision(CCollisionHull *) function, but then I guess the CCollisionHull class would have to implement some kind of GetType() function, so that the derrived classes could cast the collision hull that was passed to the TestCollision function to the correct derrived class. Is this the best way to do it, or is there a better way?
Quote:Original post by f8k8
Is this the best way to do it, or is there a better way?
This happens to be type-safe, and it's faster than a GetType-based approach as well.
Alternatively, this might make more sense semantically, and save you the hassle of defining an entire inheritance tree where none is necessary, in addition to being even safer on the long run.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement