无法在 box2d 碰撞回调中获取类数据
Posted
技术标签:
【中文标题】无法在 box2d 碰撞回调中获取类数据【英文标题】:Cannot get class data in box2d collision callback 【发布时间】:2018-11-18 16:11:02 【问题描述】:我正在用 C++ 构建一个简单的 2D 游戏,并使用 Box2D 进行碰撞检测。
我有一个Entity
类,Enemy
和Bullet
类派生自该类,EnemySquare
类派生自Enemy
类。
我正在尝试检测 EnemySquare 类和 Bullet
类之间的冲突(稍后将有更多的冲突组合需要处理)。为此,我创建了一个派生自 Box2D 类 b2ContactListener
的 CollisionManager
类,该类处理碰撞回调。
每个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 代码中做错了什么。任何建议将不胜感激!
【问题讨论】:
您好!关于static_cast
s 看看type casting。我觉得应该是reinterpret_cast
。
嘿,非常感谢您的建议,不幸的是仍然没有运气。不过我会继续研究reinterpret_cast
,感觉这是一个很好的解决方案,我只是可能需要弄清楚如何正确使用它。
【参考方案1】:
为Enemy
派生类设置m_collisionObjectType
成员变量。最好是COLLISION_OBJECT_TYPE::ENEMY
。
正如代码现在出现的那样,它只是在Bullet
派生类的代码中设置m_collisionObjectType
。因此,Enemy
派生类实例在构造时使用未初始化的 m_collisionObjectType
成员变量。 IE。 getCollisionObjectType()
方法的值可以是 m_collisionObjectType
的内存位置在构造函数使用之前的任何值。
希望这会有所帮助!
【讨论】:
以上是关于无法在 box2d 碰撞回调中获取类数据的主要内容,如果未能解决你的问题,请参考以下文章