0

I am writing some code to detect collision between different shapes, RectShape,CircShape,LineShape all inheriting from a base class Shape. My current implementation works really badly. First, I defined a bunch of case-specific functions:

bool LineLineCollision(LineShape& line1, LineShape& line2) {
    // do some math
}

bool CircRectCollision(CircShape& circ, RectShape& rect) {
    // some more math
}

// and so on for all cases

obviously all of these are required in any implementation. The issue is in the function bool TestCollision(Shape& shp1, Shape& shp2) which takes the two parameters, then goes through many if statements to compare typeid(shp1) and typeid(shp2) to the typeid of all my derived classes. It's dirty and messy but I didn't have any other ideas at the time. Now I'd like to clean it up. Adding a new type of shape is unimaginably annoying and time consuming.

My new idea right now is simply overloading TestCollision with arguments fitting different parameter types, but then I'll have to have TestCollision(CircShape&, RectShape&) and TestCollision(RectShape&, CircShape&) as two separate overloads and that's not maintainable. Another idea is to implement the functions inside the derived classes themselves, but it still results in duplication of code and is even less maintainable.

How would I tackle this issue?

3
  • 1
    It's a good time for learning the template metaprogramming in C++ using some of good C++ books. Commented Feb 6, 2021 at 18:28
  • @S.M. I had template specialization in mind, but it has two issues.The first one is how the parameters are ordered. Is it possible to take two parameter types in any order? The other thing is how I have to tell the function which types the arguments are, and that seems pointless, the compiler will be able to deduce that (I think this has to do with how Shape is a pure abstract class) Commented Feb 6, 2021 at 18:34
  • Is it possible to take two parameter types in any order? Yes, it is possible. Commented Feb 6, 2021 at 19:04

1 Answer 1

1

A solution would be to use a callback. e.g.

#include <iostream>

struct Line;
struct Circ;

struct Shape {
    virtual void Collision(Line*) = 0;
    virtual void Collision(Circ*) = 0;
    virtual void Collision(Shape*) = 0;
};

class Line : public Shape {
private:
    void Collision(Line*) override {
        std::cout << "Line-Line\n";
    }
    void Collision(Circ*) override {
        std::cout << "Circ-Line\n";
    }
public:
    void Collision(Shape* other) override {
        other->Collision(this);
    }
};

class Circ : public Shape {
private:
    void Collision(Line*) override {
        std::cout << "Line-Circ\n";
    }
    void Collision(Circ*) override {
        std::cout << "Circ-Circ\n";
    }
public:
    void Collision(Shape* other) override {
        other->Collision(this);
    }
};

#include<memory>

int main(){
    std::unique_ptr<Shape> obj1 = std::make_unique<Line>();
    std::unique_ptr<Shape> obj2 = std::make_unique<Circ>();
    std::unique_ptr<Shape> obj3 = std::make_unique<Line>();

    obj1->Collision(obj2.get());
    obj1->Collision(obj3.get());

}

outputs:

Line-Circ
Line-Line
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.