I'm writing a simple game engine and after a lot of rethinking/refactoring I settled with sort of a component based architecture (not strictly ECS, but it isn't inheritance based anymore either). So everything in my world is an entity, and each entity has got a bunch of components. Every system/subsystem in my game scans an entity for a series of components it's interested in, and performs some relevant computations.
So far so good. The engine basic architecture can be seen here:
Now, every entity that is collidable with has a collision component (along with position/movement/rigidbody components), so the physics system needs to get that component and use it to feed its collision detection algorithms, in order to generate contact data to be used to resolve the collision.
I'm stuck on the following issue: the collison detection algorithms deal with different geometries: boxes,spheres,planes and rays (as of now), but I don't want to have a spherecollisioncomponent and a boxcollisioncomponent, at least I don't want them to be unrelated but I'd like them to share some common base class.
class Sphere
{
public:
Sphere(float radius);
~Sphere();
float GetRadius() { return mRadius; }
private:
float mRadius;
};
class Box : public BoundingVolume
{
public:
Box(const XMFLOAT3 &halfSize);
~Box();
XMFLOAT3 const &GetHalfSize() const { return mHalfSize; }
private:
XMFLOAT3 mHalfSize;
};
Obviously each component has a different interface (boxes have halfsizes, spheres have a radius and so on), and the different collision detection functions deal very differently with each of them (box-box, box-sphere, sphere-sphere..).
void CollisionSystem::BoxAndBoxCollision(const Box &box1, const Box &box2)
{
// contact data
XMFLOAT3 contactPoint;
XMFLOAT3 contactNormal;
float minOverlap = 100.0f;
// get axes for SAT test
std::vector<XMFLOAT3> axes = GetSATAxes(box1, box2);
int axisIndex = 0;
int index = 0;
for (XMFLOAT3 axis : axes)
{
if (XMVectorGetX(XMVector3Length(XMLoadFloat3(&axis))) < 0.01f)
{
index++;
continue;
}
float overlap = PerformSAT(axis, box1, box2);
if (overlap < 0) // found separating axis - early out
return;
if (overlap < minOverlap)
{
minOverlap = overlap;
axisIndex = index;
}
index++;
}
// other collision detection/generation code.....
// store contact
mContacts.push_back(new Contact(box1->GetRigidBody(), box2->GetRigidBody(), contactPoint, contactNormal, minOverlap, coefficientOfRestitution));
}
So how can I solve this in an elegant and robust way?