使用开源物理引擎Box2D来实现游戏中的刚体、碰撞体、力学、约束等功能。
组件:Rigidbody2D
struct Rigidbody2DComponent
{
enum class BodyType { Static = 0, Dynamic, Kinematic };
BodyType Type = BodyType::Static;
bool FixedRotation = false;
void* RuntimeBody = nullptr;
Rigidbody2DComponent() = default;
Rigidbody2DComponent(const Rigidbody2DComponent&) = default;
};
组件:BoxCollider2D
struct BoxCollider2DComponent
{
glm::vec2 Offset = { 0.0f, 0.0f };
glm::vec2 Size = { 0.5f, 0.5f };
float Density = 1.0f;
float Friction = 0.5f;
float Restitution = 0.0f;
float RestitutionThreshold = 0.5f;
void* RuntimeFixture = nullptr;
BoxCollider2DComponent() = default;
BoxCollider2DComponent(const BoxCollider2DComponent&) = default;
};
在类Scene中,当场景开始运行时,初始化物理世界,遍历所有拥有组件Rigidbody2D的实体,利用Box2D提供的接口为其初始化物理体:
void Scene::OnRuntimeStart()
{
m_PhysicsWorld = new b2World({ 0.0f, -9.8f });
/* 遍历所以带有Rigidbody2D的实体,注意创建物理体 */
auto view = m_Registry.view<Rigidbody2DComponent>();
for (auto e : view)
{
Entity entity = { e, this };
auto& transform = entity.GetComponent<TransformComponent>();
auto& rb2d = entity.GetComponent<Rigidbody2DComponent>();
/* 设置刚体数据 */
b2BodyDef bodyDef;
bodyDef.type = Rigidbody2DTypeToBox2DBody(rb2d.Type);
bodyDef.position.Set(transform.Translation.x, transform.Translation.y);
bodyDef.angle = transform.Rotation.z;
b2Body* body = m_PhysicsWorld->CreateBody(&bodyDef);
body->SetFixedRotation(rb2d.FixedRotation);
rb2d.RuntimeBody = body;
/* 添加Box Collider */
if (entity.HasComponent<BoxCollider2DComponent>())
{
auto& bc2d = entity.GetComponent<BoxCollider2DComponent>();
b2PolygonShape boxShape;
boxShape.SetAsBox(bc2d.Size.x * transform.Scale.x, bc2d.Size.y * transform.Scale.y);
b2FixtureDef fixtureDef;
fixtureDef.shape = &boxShape;
fixtureDef.density = bc2d.Density;
fixtureDef.friction = bc2d.Friction;
fixtureDef.restitution = bc2d.Restitution;
fixtureDef.restitutionThreshold = bc2d.RestitutionThreshold;
body->CreateFixture(&fixtureDef);
}
}
}
同时,在函数Scene::OnUpdateRuntime(Timestep ts)中,当场景进行更新时,也要同步更新每个拥有物理题的实体状态:
const int32_t velocityIterations = 6;
const int32_t positionIterations = 2;
m_PhysicsWorld->Step(ts, velocityIterations, positionIterations);
/* 获取所有带RigidBody2D的实体 */
auto view = m_Registry.view<Rigidbody2DComponent>();
for (auto e : view)
{
Entity entity = { e, this };
auto& transform = entity.GetComponent<TransformComponent>();
auto& rb2d = entity.GetComponent<Rigidbody2DComponent>();
b2Body* body = (b2Body*)rb2d.RuntimeBody;
const auto& position = body->GetPosition();
transform.Translation.x = position.x;
transform.Translation.y = position.y;
transform.Rotation.z = body->GetAngle();
}

Leave a comment