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 
    Sphere(float radius);
    float GetRadius() { return mRadius; }

    float mRadius;

class Box  : public BoundingVolume
    Box(const XMFLOAT3 &halfSize);
    XMFLOAT3 const &GetHalfSize() const { return mHalfSize; }
    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)

        float overlap = PerformSAT(axis, box1, box2);

        if (overlap < 0)  // found separating axis - early out

        if (overlap < minOverlap)
            minOverlap = overlap;
            axisIndex = 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?

  • 1
    Start here: Double dispatch. See also Understanding double dispatch in C++
    – Doc Brown
    Apr 6, 2019 at 9:01
  • What is a "collision component"?
    – D Drmmr
    Apr 6, 2019 at 12:07
  • Is it not possible to genericise the collision? Surely you just need contact point and normal?
    – Ewan
    Apr 6, 2019 at 13:13
  • @Ewan even if the contact data consists of contact point, normal and interpenetration, I still use different algoritms to generate the contact data, depending on the primitives involved (box-box, sphere-box, triangle mesh-spere etc.)
    – Luca
    Apr 6, 2019 at 16:17
  • @DDrmmr now is merely a tag interface that's needed to classify a collidable sub class (geometry, a sphere, a box) as a collision component in my "ECS"
    – Luca
    Apr 6, 2019 at 18:10

1 Answer 1


I've found that the best way to do this in C++ is to use a variant (e.g. std::variant or boost::variant) to store any type of shape that you support. Then use overloaded functions to implement the collision detection algorithms. Using lambda functions (especially generic lambdas) and a little bit of clever machinery this design allows you to do single and multiple dispatching with very little boilerplate code and without the need for coupling unrelated code.

typedef std::variant<Box, Sphere> VariantShape;
std::optional<Contact> collision(const Box&, const Box&);
std::optional<Contact> collision(const Box&, const Sphere&);
std::optional<Contact> collision(const Sphere&, const Box&);
std::optional<Contact> collision(const Sphere&, const Sphere&);
std::optional<Contact> collision(const VariantShape& a, const VariantShape& b)
    std::visit ([](const auto& a, const auto& b)
        return collision(a, b);
    }, a, b);
  • Ok, I need to digest this answer, I know lambdas (I'm reading about generic lambdas in Effective Modern C++), but I don't know std::optional and std::variant
    – Luca
    Apr 6, 2019 at 16:20
  • @Luca the lambda turns a set of overloads into a function object. std::optional and std::variant are tagged unions; optional having an empty type as the other member; variant having any number of types. std::visit calls the appropriate operator()
    – Caleth
    Jan 2, 2020 at 9:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.