Я создаю простую 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. Любой совет будет оценен!