Не удается получить данные класса в обратном вызове столкновения box2d - PullRequest
0 голосов
/ 18 ноября 2018

Я создаю простую 2D-игру на C ++ и использую Box2D для обнаружения столкновений.

У меня есть класс Entity, из которого получены классы Enemy и Bullet, а класс EnemySquare получен из класса Enemy.

Я пытаюсь обнаружить коллизии между классом EnemySquare и классом Bullet (в дальнейшем будет больше комбинаций коллизий для обработки). Для этого я создал класс CollisionManager, производный от класса Box2D b2ContactListener, который обрабатывает обратные вызовы коллизий.

Каждый экземпляр Entity имеет закрытую переменную m_collisionObjectType, представляющую собой enum class типов объектов (показано ниже).

В обратном вызове BeginContact() я пытаюсь привести пользовательские данные устройства box2d к правильному типу класса, чтобы я мог наносить повреждения, отмечать маркеры для удаления и т. Д.

(несущественный код удален для простоты)

Тип объекта Enum:

enum class COLLISION_OBJECT_TYPE {BULLET, ENEMY, PLAYER};

Класс сущности

.h

class Entity
{
public:
    Entity();
    ~Entity();

    COLLISION_OBJECT_TYPE getCollisionObjectType() { return m_collisionObjectType; }

protected:

    b2Body* m_body = nullptr;
    b2Fixture* m_fixtures[3];
    COLLISION_OBJECT_TYPE m_collisionObjectType;

};

Класс противника

.h

class Enemy : public Entity
{
public:
    Enemy();
    ~Enemy();
    virtual void init(glm::vec2 position, float health, float speed, Player* player, b2World* physicsWorld) = 0;
    virtual void update(float deltaTime) = 0;

protected:

    float m_health;
    float m_speed;
    Player* m_playerTarget;

};

Класс противника

.h

class EnemySquare : public Enemy
{
public:
    EnemySquare();
    ~EnemySquare();

    void init(glm::vec2 position, float health, float speed, Player* player, b2World* physicsWorld) override;
    void update(float deltaTime) override;

};

.cpp

void EnemySquare::init(glm::vec2 position, float health, float speed, Player * player, b2World* physicsWorld) {

    // init physics body
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(m_position.x, m_position.y);
    bodyDef.fixedRotation = false;
    bodyDef.angle = 0;
    bodyDef.userData = this;
    m_body = physicsWorld->CreateBody(&bodyDef);

    // init physics fixtures
    b2PolygonShape squareShape;
    squareShape.SetAsBox(m_width * 0.5f, m_height * 0.5f);
    b2FixtureDef fixtureDef;
    fixtureDef.shape = &squareShape;
    m_fixtures[0] = m_body->CreateFixture(&fixtureDef);

}

Пуля Класс

.h

class Bullet : public Entity
{
public:
    Bullet(
        b2World* world,
        glm::vec2 startPosition,
        glm::vec2 direction,
        Tempest::glTexture texture,
        float width,
        float height,
        float damage,
        float speed,
        float range
    );
    ~Bullet();

    // methods are unrelated

private:
    // private variables are unrelated

};

.cpp

Bullet::Bullet(
    b2World* world,
    glm::vec2 startPosition,
    glm::vec2 direction,
    Tempest::glTexture texture,
    float width,
    float height,
    float damage,
    float speed,
    float range
) {

    // Make the body
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(m_position.x, m_position.y);
    bodyDef.fixedRotation = true;
    bodyDef.angle = 0;
    bodyDef.userData = this;
    m_body = world->CreateBody(&bodyDef);

    // Create the box
    b2PolygonShape boxShape;
    boxShape.SetAsBox(m_height * 0.4f, m_width * 0.5f);

    b2FixtureDef boxDef;
    boxDef.shape = &boxShape;
    m_fixtures[0] = m_body->CreateFixture(&boxDef);

    m_collided = false;

    m_collisionObjectType = COLLISION_OBJECT_TYPE::BULLET;

}

В моем классе CollisionManager я пытаюсь получить пользовательские данные встречного прибора (который является пустым *), а затем преобразовать их в Entity* для вызова метода getCollisionObjectType(). Когда я знаю, с каким типом сущности я имею дело, я хочу привести его к правильному типу объекта и выполнить такие действия, как нанесение урона, пометка пуль для удаления и т. Д. Код ниже:

void CollisionManager::BeginContact(b2Contact * contact) {

    void* fixtureABodyData = contact->GetFixtureA()->GetBody()->GetUserData();
    void* fixtureBBodyData = contact->GetFixtureB()->GetBody()->GetUserData();
    if (fixtureABodyData && fixtureBBodyData) {
        Entity* fixtureAData = static_cast<Entity*>(fixtureABodyData);
        Entity* fixtureBData = static_cast<Entity*>(fixtureBBodyData);
        if (fixtureAData->getCollisionObjectType() == COLLISION_OBJECT_TYPE::BULLET) {
            std::cout << "A BULLET" << std::endl;
        }
        if (fixtureBData->getCollisionObjectType() == COLLISION_OBJECT_TYPE::BULLET) {
            std::cout << "B BULLET" << std::endl;
        }
        if (fixtureAData->getCollisionObjectType() == COLLISION_OBJECT_TYPE::ENEMY) {
            std::cout << "A ENEMY" << std::endl;
        }
        if (fixtureBData->getCollisionObjectType() == COLLISION_OBJECT_TYPE::ENEMY) {
            std::cout << "B ENEMY" << std::endl;
        }
        std::cout << "----------------------" << std::endl;
}

}

По какой-то причине кастинг работает для класса Bullet, но не для класса Enemy. Я думаю, что это возвращает nullptr. Итак, я знаю, что одно из сталкивающихся тел - это пуля, но я не могу сказать, что такое второе тело.

У меня такое ощущение, что я что-то не так делаю с вызовами static_cast или это может быть из-за того, что класс EnemySquare дважды удаляется из класса Entity? или я мог сделать что-то не так в коде Box2D. Любой совет будет оценен!

1 Ответ

0 голосов
/ 25 ноября 2018

Установите переменную-член m_collisionObjectType для производного класса Enemy. Предпочтительно до COLLISION_OBJECT_TYPE::ENEMY.

Поскольку код появляется сейчас, он только устанавливает m_collisionObjectType в коде для производного класса Bullet. Таким образом, экземпляры производных классов Enemy создаются с неинициализированными переменными-членами m_collisionObjectType. То есть значение метода getCollisionObjectType() может быть любым, что было в ячейке памяти m_collisionObjectType до его использования конструктором.

Надеюсь, это поможет!

...