Physics2D: Fix the way newly physics entities are setup
This commit is contained in:
parent
3e99ce6be5
commit
883b54e6d3
|
|
@ -98,6 +98,8 @@ namespace Nz
|
||||||
void SetVelocity(const Vector2f& velocity);
|
void SetVelocity(const Vector2f& velocity);
|
||||||
void SetVelocityFunction(VelocityFunc velocityFunc);
|
void SetVelocityFunction(VelocityFunc velocityFunc);
|
||||||
|
|
||||||
|
void TeleportTo(const Vector2f& position, const RadianAnglef& rotation);
|
||||||
|
|
||||||
void UpdateVelocity(const Vector2f& gravity, float damping, float deltaTime);
|
void UpdateVelocity(const Vector2f& gravity, float damping, float deltaTime);
|
||||||
|
|
||||||
void Wakeup();
|
void Wakeup();
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,8 @@ namespace Nz
|
||||||
Physics2DSystem& operator=(Physics2DSystem&&) = delete;
|
Physics2DSystem& operator=(Physics2DSystem&&) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void OnConstruct(entt::registry& registry, entt::entity entity);
|
|
||||||
|
|
||||||
entt::registry& m_registry;
|
entt::registry& m_registry;
|
||||||
|
entt::observer m_physicsConstructObserver;
|
||||||
entt::scoped_connection m_constructConnection;
|
entt::scoped_connection m_constructConnection;
|
||||||
PhysWorld2D m_physWorld;
|
PhysWorld2D m_physWorld;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -135,12 +135,12 @@ namespace Nz
|
||||||
cpBodySetTorque(m_handle, cpBodyGetTorque(m_handle) + torque.value);
|
cpBodySetTorque(m_handle, cpBodyGetTorque(m_handle) + torque.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RigidBody2D::ClosestPointQuery(const Nz::Vector2f& position, Nz::Vector2f* closestPoint, float* closestDistance) const
|
bool RigidBody2D::ClosestPointQuery(const Vector2f& position, Vector2f* closestPoint, float* closestDistance) const
|
||||||
{
|
{
|
||||||
cpVect pos = cpv(cpFloat(position.x), cpFloat(position.y));
|
cpVect pos = cpv(cpFloat(position.x), cpFloat(position.y));
|
||||||
|
|
||||||
float minDistance = std::numeric_limits<float>::infinity();
|
float minDistance = std::numeric_limits<float>::infinity();
|
||||||
Nz::Vector2f closest;
|
Vector2f closest;
|
||||||
for (cpShape* shape : m_shapes)
|
for (cpShape* shape : m_shapes)
|
||||||
{
|
{
|
||||||
cpPointQueryInfo result;
|
cpPointQueryInfo result;
|
||||||
|
|
@ -179,7 +179,7 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody2D::ForEachArbiter(std::function<void(Nz::Arbiter2D&)> callback)
|
void RigidBody2D::ForEachArbiter(std::function<void(Arbiter2D&)> callback)
|
||||||
{
|
{
|
||||||
using CallbackType = decltype(callback);
|
using CallbackType = decltype(callback);
|
||||||
|
|
||||||
|
|
@ -196,7 +196,7 @@ namespace Nz
|
||||||
|
|
||||||
void RigidBody2D::ForceSleep()
|
void RigidBody2D::ForceSleep()
|
||||||
{
|
{
|
||||||
m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body)
|
m_world->RegisterPostStep(this, [](RigidBody2D* body)
|
||||||
{
|
{
|
||||||
if (cpBodyGetType(body->GetHandle()) == CP_BODY_TYPE_DYNAMIC)
|
if (cpBodyGetType(body->GetHandle()) == CP_BODY_TYPE_DYNAMIC)
|
||||||
cpBodySleep(body->GetHandle());
|
cpBodySleep(body->GetHandle());
|
||||||
|
|
@ -221,13 +221,13 @@ namespace Nz
|
||||||
return float(cpBodyGetAngularVelocity(m_handle));
|
return float(cpBodyGetAngularVelocity(m_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
float Nz::RigidBody2D::GetElasticity(std::size_t shapeIndex) const
|
float RigidBody2D::GetElasticity(std::size_t shapeIndex) const
|
||||||
{
|
{
|
||||||
assert(shapeIndex < m_shapes.size());
|
assert(shapeIndex < m_shapes.size());
|
||||||
return float(cpShapeGetElasticity(m_shapes[shapeIndex]));
|
return float(cpShapeGetElasticity(m_shapes[shapeIndex]));
|
||||||
}
|
}
|
||||||
|
|
||||||
float Nz::RigidBody2D::GetFriction(std::size_t shapeIndex) const
|
float RigidBody2D::GetFriction(std::size_t shapeIndex) const
|
||||||
{
|
{
|
||||||
assert(shapeIndex < m_shapes.size());
|
assert(shapeIndex < m_shapes.size());
|
||||||
return float(cpShapeGetFriction(m_shapes[shapeIndex]));
|
return float(cpShapeGetFriction(m_shapes[shapeIndex]));
|
||||||
|
|
@ -290,7 +290,7 @@ namespace Nz
|
||||||
return std::distance(m_shapes.begin(), it);
|
return std::distance(m_shapes.begin(), it);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2f Nz::RigidBody2D::GetSurfaceVelocity(std::size_t shapeIndex) const
|
Vector2f RigidBody2D::GetSurfaceVelocity(std::size_t shapeIndex) const
|
||||||
{
|
{
|
||||||
assert(shapeIndex < m_shapes.size());
|
assert(shapeIndex < m_shapes.size());
|
||||||
cpVect vel = cpShapeGetSurfaceVelocity(m_shapes[shapeIndex]);
|
cpVect vel = cpShapeGetSurfaceVelocity(m_shapes[shapeIndex]);
|
||||||
|
|
@ -421,7 +421,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
if (mass > 0.f)
|
if (mass > 0.f)
|
||||||
{
|
{
|
||||||
m_world->RegisterPostStep(this, [mass, recomputeMoment](Nz::RigidBody2D* body)
|
m_world->RegisterPostStep(this, [mass, recomputeMoment](RigidBody2D* body)
|
||||||
{
|
{
|
||||||
cpBodySetMass(body->GetHandle(), mass);
|
cpBodySetMass(body->GetHandle(), mass);
|
||||||
|
|
||||||
|
|
@ -430,11 +430,11 @@ namespace Nz
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) { cpBodySetType(body->GetHandle(), (body->IsStatic()) ? CP_BODY_TYPE_STATIC : CP_BODY_TYPE_KINEMATIC); } );
|
m_world->RegisterPostStep(this, [](RigidBody2D* body) { cpBodySetType(body->GetHandle(), (body->IsStatic()) ? CP_BODY_TYPE_STATIC : CP_BODY_TYPE_KINEMATIC); } );
|
||||||
}
|
}
|
||||||
else if (mass > 0.f)
|
else if (mass > 0.f)
|
||||||
{
|
{
|
||||||
m_world->RegisterPostStep(this, [mass, recomputeMoment](Nz::RigidBody2D* body)
|
m_world->RegisterPostStep(this, [mass, recomputeMoment](RigidBody2D* body)
|
||||||
{
|
{
|
||||||
if (cpBodyGetType(body->GetHandle()) != CP_BODY_TYPE_DYNAMIC)
|
if (cpBodyGetType(body->GetHandle()) != CP_BODY_TYPE_DYNAMIC)
|
||||||
{
|
{
|
||||||
|
|
@ -470,7 +470,7 @@ namespace Nz
|
||||||
void RigidBody2D::SetMomentOfInertia(float moment)
|
void RigidBody2D::SetMomentOfInertia(float moment)
|
||||||
{
|
{
|
||||||
// Even though Chipmunk allows us to change this anytime, we need to do it in a post-step to prevent other post-steps to override this
|
// Even though Chipmunk allows us to change this anytime, we need to do it in a post-step to prevent other post-steps to override this
|
||||||
m_world->RegisterPostStep(this, [moment] (Nz::RigidBody2D* body)
|
m_world->RegisterPostStep(this, [moment] (RigidBody2D* body)
|
||||||
{
|
{
|
||||||
cpBodySetMoment(body->GetHandle(), moment);
|
cpBodySetMoment(body->GetHandle(), moment);
|
||||||
});
|
});
|
||||||
|
|
@ -482,7 +482,7 @@ namespace Nz
|
||||||
cpBodySetPosition(m_handle, cpvadd(cpv(position.x, position.y), cpTransformVect(m_handle->transform, cpv(m_positionOffset.x, m_positionOffset.y))));
|
cpBodySetPosition(m_handle, cpvadd(cpv(position.x, position.y), cpTransformVect(m_handle->transform, cpv(m_positionOffset.x, m_positionOffset.y))));
|
||||||
if (m_isStatic)
|
if (m_isStatic)
|
||||||
{
|
{
|
||||||
m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body)
|
m_world->RegisterPostStep(this, [](RigidBody2D* body)
|
||||||
{
|
{
|
||||||
cpSpaceReindexShapesForBody(body->GetWorld()->GetHandle(), body->GetHandle());
|
cpSpaceReindexShapesForBody(body->GetWorld()->GetHandle(), body->GetHandle());
|
||||||
});
|
});
|
||||||
|
|
@ -491,7 +491,7 @@ namespace Nz
|
||||||
|
|
||||||
void RigidBody2D::SetPositionOffset(const Vector2f& offset)
|
void RigidBody2D::SetPositionOffset(const Vector2f& offset)
|
||||||
{
|
{
|
||||||
Nz::Vector2f position = GetPosition();
|
Vector2f position = GetPosition();
|
||||||
m_positionOffset = offset;
|
m_positionOffset = offset;
|
||||||
SetPosition(position);
|
SetPosition(position);
|
||||||
}
|
}
|
||||||
|
|
@ -501,7 +501,7 @@ namespace Nz
|
||||||
cpBodySetAngle(m_handle, rotation.value);
|
cpBodySetAngle(m_handle, rotation.value);
|
||||||
if (m_isStatic)
|
if (m_isStatic)
|
||||||
{
|
{
|
||||||
m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body)
|
m_world->RegisterPostStep(this, [](RigidBody2D* body)
|
||||||
{
|
{
|
||||||
cpSpaceReindexShapesForBody(body->GetWorld()->GetHandle(), body->GetHandle());
|
cpSpaceReindexShapesForBody(body->GetWorld()->GetHandle(), body->GetHandle());
|
||||||
});
|
});
|
||||||
|
|
@ -524,7 +524,7 @@ namespace Nz
|
||||||
void RigidBody2D::SetStatic(bool setStaticBody)
|
void RigidBody2D::SetStatic(bool setStaticBody)
|
||||||
{
|
{
|
||||||
m_isStatic = setStaticBody;
|
m_isStatic = setStaticBody;
|
||||||
m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body)
|
m_world->RegisterPostStep(this, [](RigidBody2D* body)
|
||||||
{
|
{
|
||||||
if (body->IsStatic())
|
if (body->IsStatic())
|
||||||
{
|
{
|
||||||
|
|
@ -560,21 +560,35 @@ namespace Nz
|
||||||
const auto& callback = rigidBody->GetVelocityFunction();
|
const auto& callback = rigidBody->GetVelocityFunction();
|
||||||
assert(callback);
|
assert(callback);
|
||||||
|
|
||||||
callback(*rigidBody, Nz::Vector2f(float(gravity.x), float(gravity.y)), float(damping), float(dt));
|
callback(*rigidBody, Vector2f(float(gravity.x), float(gravity.y)), float(damping), float(dt));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_handle->velocity_func = cpBodyUpdateVelocity;
|
m_handle->velocity_func = cpBodyUpdateVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody2D::UpdateVelocity(const Nz::Vector2f & gravity, float damping, float deltaTime)
|
void RigidBody2D::TeleportTo(const Vector2f& position, const RadianAnglef& rotation)
|
||||||
|
{
|
||||||
|
// Use cpTransformVect to rotate/scale the position offset
|
||||||
|
cpBodySetPosition(m_handle, cpvadd(cpv(position.x, position.y), cpTransformVect(m_handle->transform, cpv(m_positionOffset.x, m_positionOffset.y))));
|
||||||
|
cpBodySetAngle(m_handle, rotation.value);
|
||||||
|
if (m_isStatic)
|
||||||
|
{
|
||||||
|
m_world->RegisterPostStep(this, [](RigidBody2D* body)
|
||||||
|
{
|
||||||
|
cpSpaceReindexShapesForBody(body->GetWorld()->GetHandle(), body->GetHandle());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RigidBody2D::UpdateVelocity(const Vector2f & gravity, float damping, float deltaTime)
|
||||||
{
|
{
|
||||||
cpBodyUpdateVelocity(m_handle, cpv(gravity.x, gravity.y), damping, deltaTime);
|
cpBodyUpdateVelocity(m_handle, cpv(gravity.x, gravity.y), damping, deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody2D::Wakeup()
|
void RigidBody2D::Wakeup()
|
||||||
{
|
{
|
||||||
m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body)
|
m_world->RegisterPostStep(this, [](RigidBody2D* body)
|
||||||
{
|
{
|
||||||
if (cpBodyGetType(body->GetHandle()) != CP_BODY_TYPE_STATIC)
|
if (cpBodyGetType(body->GetHandle()) != CP_BODY_TYPE_STATIC)
|
||||||
cpBodyActivate(body->GetHandle());
|
cpBodyActivate(body->GetHandle());
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
inline Nz::RadianAnglef AngleFromQuaternion(const Nz::Quaternionf& quat)
|
inline RadianAnglef AngleFromQuaternion(const Quaternionf& quat)
|
||||||
{
|
{
|
||||||
float siny_cosp = 2.f * (quat.w * quat.z + quat.x * quat.y);
|
float siny_cosp = 2.f * (quat.w * quat.z + quat.x * quat.y);
|
||||||
float cosy_cosp = 1.f - 2.f * (quat.y * quat.y + quat.z * quat.z);
|
float cosy_cosp = 1.f - 2.f * (quat.y * quat.y + quat.z * quat.z);
|
||||||
|
|
@ -20,14 +20,16 @@ namespace Nz
|
||||||
}
|
}
|
||||||
|
|
||||||
Physics2DSystem::Physics2DSystem(entt::registry& registry) :
|
Physics2DSystem::Physics2DSystem(entt::registry& registry) :
|
||||||
m_registry(registry)
|
m_registry(registry),
|
||||||
|
m_physicsConstructObserver(m_registry, entt::collector.group<RigidBody2DComponent, NodeComponent>())
|
||||||
{
|
{
|
||||||
m_constructConnection = registry.on_construct<RigidBody2DComponent>().connect<OnConstruct>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Physics2DSystem::~Physics2DSystem()
|
Physics2DSystem::~Physics2DSystem()
|
||||||
{
|
{
|
||||||
// Ensure every NewtonBody is destroyed before world is
|
m_physicsConstructObserver.disconnect();
|
||||||
|
|
||||||
|
// Ensure every body is destroyed before world is
|
||||||
auto rigidBodyView = m_registry.view<RigidBody2DComponent>();
|
auto rigidBodyView = m_registry.view<RigidBody2DComponent>();
|
||||||
for (auto [entity, rigidBodyComponent] : rigidBodyView.each())
|
for (auto [entity, rigidBodyComponent] : rigidBodyView.each())
|
||||||
rigidBodyComponent.Destroy();
|
rigidBodyComponent.Destroy();
|
||||||
|
|
@ -35,6 +37,15 @@ namespace Nz
|
||||||
|
|
||||||
void Physics2DSystem::Update(Time elapsedTime)
|
void Physics2DSystem::Update(Time elapsedTime)
|
||||||
{
|
{
|
||||||
|
// Move newly-created physics entities to their node position/rotation
|
||||||
|
m_physicsConstructObserver.each([&](entt::entity entity)
|
||||||
|
{
|
||||||
|
RigidBody2DComponent& entityPhysics = m_registry.get<RigidBody2DComponent>(entity);
|
||||||
|
NodeComponent& entityNode = m_registry.get<NodeComponent>(entity);
|
||||||
|
|
||||||
|
entityPhysics.TeleportTo(Vector2f(entityNode.GetPosition()), AngleFromQuaternion(entityNode.GetRotation()));
|
||||||
|
});
|
||||||
|
|
||||||
m_physWorld.Step(elapsedTime);
|
m_physWorld.Step(elapsedTime);
|
||||||
|
|
||||||
// Replicate rigid body position to their node components
|
// Replicate rigid body position to their node components
|
||||||
|
|
@ -44,20 +55,7 @@ namespace Nz
|
||||||
if (rigidBodyComponent.IsSleeping())
|
if (rigidBodyComponent.IsSleeping())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nodeComponent.SetPosition(rigidBodyComponent.GetPosition(), CoordSys::Global);
|
nodeComponent.SetTransform(rigidBodyComponent.GetPosition(), rigidBodyComponent.GetRotation());
|
||||||
nodeComponent.SetRotation(rigidBodyComponent.GetRotation(), CoordSys::Global);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Physics2DSystem::OnConstruct(entt::registry& registry, entt::entity entity)
|
|
||||||
{
|
|
||||||
// If our entity already has a node component when adding a rigid body, initialize it with its position/rotation
|
|
||||||
NodeComponent* node = registry.try_get<NodeComponent>(entity);
|
|
||||||
if (node)
|
|
||||||
{
|
|
||||||
RigidBody2DComponent& rigidBody = registry.get<RigidBody2DComponent>(entity);
|
|
||||||
rigidBody.SetPosition(Vector2f(node->GetPosition()));
|
|
||||||
rigidBody.SetRotation(AngleFromQuaternion(node->GetRotation()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue