在box2d碰撞回调中无法获取类数据

时间:2018-11-18 16:11:03

标签: c++ box2d

我正在用C ++构建一个简单的2D游戏,并使用Box2D进行碰撞检测。

我有一个Entity类,从中派生一个EnemyBullet类,而一个EnemySquare类派生自Enemy类。 / p>

我正在尝试检测EnemySquare类和Bullet类之间的冲突(将有更多冲突组合在以后的开发中进行处理)。为此,我创建了一个CollisionManager类,它是从Box2D类b2ContactListener派生的,该类处理碰撞回调。

每个Entity实例都有一个私有变量m_collisionObjectType,它是对象类型的enum class(如下所示)。

BeginContact()回调中,我试图将box2d灯具的用户数据转换为正确的类类型,以便可以施加损坏,标记要删除的项目符号等。

(为简化起见,删除了无关代码)

对象类型枚举:

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类中,我试图检索碰撞夹具的userData(它是一个void *),然后将其转换为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 :(得分:0)

m_collisionObjectType派生类设置Enemy成员变量。最好是COLLISION_OBJECT_TYPE::ENEMY

如代码现在所示,它只是在m_collisionObjectType派生类的代码中设置Bullet。因此,Enemy派生的类实例是在其m_collisionObjectType成员变量未初始化的情况下构造的。即getCollisionObjectType()方法中的值可以是m_collisionObjectType的内存位置在构造函数使用之前的值。

希望这会有所帮助!