WAYNETS.ORG

Game and Program

物理系统

作者:

发表于

Context Polling System Post-Processing Renderer

使用开源物理引擎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