Использование dynamic_cast для обнаружения столкновений в 2D-среде

0

Я разрабатываю базу для 2D-игры. Мой общий дизайн выглядит примерно так:

class Entity:
    Every object class (like a wall, an enemy, floor etc.) derives
    from this class. Most of the functions are pure virtual. There is
    a hitbox as well.

class Scene:
    Contains pointers to Entity-objects. When an Entity-pointer is added,
    it will be given a Scene-pointer to its parent so it may access that.

Сцена также имеет функцию обнаружения столкновения:

getIntersections<T> (Entity *)
getIntersections<T...> (Entity *)
    (both return a std::vector<Entity *>)

Это в основном получает все Entity * пересекающие parameter- Entity * (путем проверки hitbox), а затем пытается использовать dynamic_cast<T *>. Затем возвращаются все соответствующие Entity * (а не литые). Вариационный шаблон используется для проверки более одного пересекающегося класса.

Моя основная идея заключалась в том, что если бы у меня был Player -class (который явно представляет игрока) и некоторые другие классы, такие как Enemy, Wall и т.д., Было бы легкой задачей проверить, был ли Player -object сталкиваясь с одним (или более) из них:

// (inside Player::tick(); quick and dirty)
{
    if ( (this->parentScene->getIntersections<Wall>(this)).empty() )
        // player does not collide with a wall, just move.
    else
        // player does collide with a wall, do whatever.
}

Однако у меня есть два вопроса:

  1. Мой (общий) дизайн обнаруживает недостатки для необходимости dynamic_cast<T *> качестве замены для instanceof (например, в Java)
  2. Является ли это решающим решением задачи? Так как для каждой проверки столкновения Scene основном проходит через каждую содержащуюся в ней Entity *, проверяет, сталкивается ли она с данным Entity * и, наконец, бросает ее, чтобы проверить, вытекает ли она из другого данного класса. Если это не работает, какие изменения должны были сделать в моем дизайне, чтобы сделать его работоспособным?
Теги:
c++11
variadic-templates
collision-detection

1 ответ

1
Лучший ответ

В части производительности было бы лучше отделить объекты в отдельных векторах примитивным типом. Не только вы можете специально протестировать плоскость и сферу, например, это избавляет от необходимости иметь dynamic_cast полностью (-> дополнительное ускорение). Кроме того, поскольку вы уже разделили типы в векторах, вы можете просто игнорировать виртуальные функции и перейти на не виртуальный вызов, обеспечивающий дополнительное повышение производительности; Таким образом, ваша сцена будет выглядеть примерно так:

class scene
{
    std::vector<PlaneEntity> m_planes;
    std::vector<CircleEntity> m_circles;
};

И в отношении дизайна этого гораздо проще выбрать правильный алгоритм при пересечении примитивов: это пример того, как будет выглядеть базовая проверка столкновения на основе этого дизайна:

void colide(const PlaneEntity & e)
{
    for each plane
        call plane vs plane collision
    for each circle
        call plane vs circle collision;
};
void colide(const CircleEntity & e)
{
    for each plane
        call plane vs circle collision;
    for each circle
        call circle vs circle collision;
};

Поэтому, чтобы ответить на ваш вопрос:

1: это не правило погоды использовать или не dynamic_cast, известно, что не использовать его лучше для производительности.

2: Конструкция, описанная выше, вообще не работает. Также ваш дизайн с динамическим приводом еще медленнее. Чтобы улучшить это, вам нужно изучить структуры ускорений (это огромная тема, поэтому я не могу все объяснить здесь), чтобы ускорить обнаружение столкновений. Они в основном уменьшают количество проверок столкновения для каждого примитива, что дает значительное улучшение производительности. Основными структурами являются KD-Tree, Quad-Trees, Spacial-Hash, Grid и т.д. Вы можете найти много кода для каждого, просто выполнив их.

Надеюсь, это поможет, Раксван.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню