У меня есть круги, коробки и линии. И теперь я хочу реализовать обнаружение столкновений между ними. Это означает, что у меня должна быть функция для каждой комбинации двух видов фигур. Конечно, я могу использовать то же самое для линии против круга и круга против линии, но я думаю, что моя точка зрения остается неизменной. Какой самый элегантный способ реализовать это в C ++?
в Современный дизайн C ++ В книге, глава «Мультиметоды», объясняется, как их реализовать, и документируется, как ее использовать [реализация предоставлена библиотекой Loki] [2]. Существует также Boost.Multimethod предложение, но это еще не там. Книга демонстрирует мощь мультиметодов именно на тему столкновения объектов.
Полиморфизм
сначала у вас есть Shape
и все остальные подклассы:
class Shape;
class Circle : Shape;
class Square : Shape;
...etc
и вы хотите, чтобы все они пересекались друг с другом, поэтому у вас есть одна общая функция:
class Shape{
bool isIntersect(const Shape&)
{
return isIntersecting(this, shape);
}
};
Теперь перегрузите isInsesect со всеми параметрами пары, так как каждый случай уникален, у вас нет особого выбора, кроме как реализовать каждый случай:
bool isIntersecting(Circle, Square);
bool isIntersecting(Circle, Line);
...
Вы также можете попробовать шаблон посетителя, но я думаю, что он здесь бесполезен.
Вы можете обнаруживать столкновения в сцене и не обрабатывать каждый инцидент двух форм.
Кроме того, вы столкнетесь с некоторыми проблемами. Среди них тип выбивания и регистрация геометрических фигур:
#include <iostream>
#include <map>
class Shape
{
public:
struct Type {
public:
typedef unsigned Identifier;
const char* name;
Identifier id;
Type(const char* name)
: name(name), id(register_name(name))
{}
private:
static Identifier register_name(const char*);
};virtual const Type& get_type() const = 0;
virtual ~Shape() {}
};
Shape::Type::Identifier Shape::Type::register_name(const char* name) {
typedef std::map<const char*, Identifier> Types;
static std::map<const char*, Identifier> types;
auto& id = types[name];
if( ! id) id = types.size();
return id;
}class Scene
{
public:
typedef bool (*CollisionDetector)(const Shape&, const Shape&);
void register_collision_detector(CollisionDetector, const Shape::Type&, const Shape::Type&);
bool collision(const Shape& a, const Shape&, bool strict = false) const;
private:
typedef std::pair<Shape::Type::Identifier, Shape::Type::Identifier> Identifier;
typedef std::map<Identifier, CollisionDetector> CollisionDetectors;
CollisionDetectors m_detectors;
};
void Scene::register_collision_detector(
CollisionDetector detector,
const Shape::Type& t0,
const Shape::Type& t1)
{
m_detectors[Identifier(t0.id, t1.id)] = detector;
}
bool Scene::collision(const Shape& s0, const Shape& s1, bool strict) const {
const Shape::Type::Identifier i0 = s0.get_type().id;
const Shape::Type::Identifier i1 = s1.get_type().id;
auto pos = m_detectors.find(Identifier(i0, i1));
if(pos == m_detectors.end() && ! strict && i0 != i1)
pos = m_detectors.find(Identifier(i1, i0));
if(pos != m_detectors.end())
return pos->second(s0, s1);
else return false;
}class Circle : public Shape
{
public:
static const Type type;
virtual const Type& get_type() const { return type; }
};
const Shape::Type Circle::type("Circle");
class Rectangle : public Shape
{
public:
static const Type type;
virtual const Type& get_type() const { return type; }
};
const Shape::Type Rectangle::type("Rectangle");
bool circle_rectangle_collision(const Shape& circle, const Shape& rectangle) {
std::cout << "circle_rectangle_collision" << std::endl;
return false;
}int main()
{
Scene scene;
scene.register_collision_detector(circle_rectangle_collision, Circle::type, Rectangle::type);
Circle circle;
Rectangle rectangle;
scene.collision(circle, rectangle);
scene.collision(rectangle, circle);
}