|
|
|
|
@@ -33,6 +33,9 @@ void EditorPhysicsSystem::update(float deltaTime)
|
|
|
|
|
|
|
|
|
|
// Step physics
|
|
|
|
|
m_physics->update(deltaTime);
|
|
|
|
|
|
|
|
|
|
// Update SceneNodes from physics for dynamic bodies
|
|
|
|
|
updateDynamicBodies();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorPhysicsSystem::syncBodies()
|
|
|
|
|
@@ -43,8 +46,75 @@ void EditorPhysicsSystem::syncBodies()
|
|
|
|
|
m_rigidBodyQuery.each([&](flecs::entity entity,
|
|
|
|
|
RigidBodyComponent& rigidBody,
|
|
|
|
|
TransformComponent& transform) {
|
|
|
|
|
// Handle enabled/disabled state
|
|
|
|
|
if (!rigidBody.enabled) {
|
|
|
|
|
// Body is disabled - remove from physics if it exists
|
|
|
|
|
if (rigidBody.bodyCreated) {
|
|
|
|
|
removeRigidBody(rigidBody);
|
|
|
|
|
}
|
|
|
|
|
return; // Skip rest of processing for disabled bodies
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Body is enabled
|
|
|
|
|
if (rigidBody.bodyDirty || !rigidBody.bodyCreated) {
|
|
|
|
|
// Create or recreate the body
|
|
|
|
|
// When transitioning from disabled to enabled, this will sync SceneNode -> physics
|
|
|
|
|
updateRigidBody(entity, rigidBody, transform);
|
|
|
|
|
} else if (rigidBody.bodyCreated && transform.node) {
|
|
|
|
|
// Body exists and is enabled - handle per-body-type updates
|
|
|
|
|
switch (rigidBody.bodyType) {
|
|
|
|
|
case RigidBodyComponent::BodyType::Dynamic:
|
|
|
|
|
// Dynamic: Physics controls position, SceneNode is updated after physics step
|
|
|
|
|
// Nothing to do here - updateDynamicBodies handles SceneNode update
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RigidBodyComponent::BodyType::Static:
|
|
|
|
|
// Static: SceneNode controls position
|
|
|
|
|
// Sync SceneNode -> physics when transform changes
|
|
|
|
|
m_physics->setPositionAndRotation(
|
|
|
|
|
rigidBody.bodyID,
|
|
|
|
|
transform.node->_getDerivedPosition(),
|
|
|
|
|
transform.node->_getDerivedOrientation(),
|
|
|
|
|
false);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RigidBodyComponent::BodyType::Kinematic:
|
|
|
|
|
// Kinematic: SceneNode controls position (moved by code, not forces)
|
|
|
|
|
// Sync SceneNode -> physics every frame
|
|
|
|
|
m_physics->setPositionAndRotation(
|
|
|
|
|
rigidBody.bodyID,
|
|
|
|
|
transform.node->_getDerivedPosition(),
|
|
|
|
|
transform.node->_getDerivedOrientation(),
|
|
|
|
|
false);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EditorPhysicsSystem::updateDynamicBodies()
|
|
|
|
|
{
|
|
|
|
|
if (!m_initialized || !m_physics) return;
|
|
|
|
|
|
|
|
|
|
// Update SceneNode positions from physics for dynamic bodies
|
|
|
|
|
m_rigidBodyQuery.each([&](flecs::entity entity,
|
|
|
|
|
RigidBodyComponent& rigidBody,
|
|
|
|
|
TransformComponent& transform) {
|
|
|
|
|
if (!rigidBody.enabled || !rigidBody.bodyCreated || !transform.node)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (rigidBody.bodyType == RigidBodyComponent::BodyType::Dynamic) {
|
|
|
|
|
// Get position and rotation from physics body
|
|
|
|
|
Ogre::Vector3 position = m_physics->getPosition(rigidBody.bodyID);
|
|
|
|
|
Ogre::Quaternion rotation = m_physics->getRotation(rigidBody.bodyID);
|
|
|
|
|
|
|
|
|
|
// Update SceneNode
|
|
|
|
|
transform.node->_setDerivedPosition(position);
|
|
|
|
|
transform.node->_setDerivedOrientation(rotation);
|
|
|
|
|
|
|
|
|
|
// Also update the Transform component to match
|
|
|
|
|
transform.position = position;
|
|
|
|
|
transform.rotation = rotation;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
@@ -73,7 +143,7 @@ JPH::ShapeRefC EditorPhysicsSystem::createShape(PhysicsColliderComponent& collid
|
|
|
|
|
}
|
|
|
|
|
case PhysicsColliderComponent::ShapeType::Cylinder: {
|
|
|
|
|
result = m_physics->createCylinderShape(collider.halfHeight,
|
|
|
|
|
collider.radius);
|
|
|
|
|
collider.radius);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case PhysicsColliderComponent::ShapeType::Mesh: {
|
|
|
|
|
@@ -173,7 +243,7 @@ void EditorPhysicsSystem::updateRigidBody(flecs::entity entity,
|
|
|
|
|
removeRigidBody(rigidBody);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for mesh colliders on dynamic bodies (not supported by Jolt)
|
|
|
|
|
// Check for mesh colliders - they only work with Static bodies
|
|
|
|
|
bool hasMeshCollider = false;
|
|
|
|
|
entity.children([&](flecs::entity child) {
|
|
|
|
|
if (child.has<PhysicsColliderComponent>()) {
|
|
|
|
|
@@ -184,10 +254,23 @@ void EditorPhysicsSystem::updateRigidBody(flecs::entity entity,
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (hasMeshCollider && rigidBody.bodyType == RigidBodyComponent::BodyType::Dynamic) {
|
|
|
|
|
if (hasMeshCollider && rigidBody.bodyType != RigidBodyComponent::BodyType::Static) {
|
|
|
|
|
Ogre::LogManager::getSingleton().logMessage(
|
|
|
|
|
"WARNING: Mesh colliders can only be used with Static or Kinematic bodies, not Dynamic."
|
|
|
|
|
" The body will be created but may not behave correctly.");
|
|
|
|
|
"ERROR: Mesh colliders can only be used with Static bodies. "
|
|
|
|
|
"Body type is " +
|
|
|
|
|
std::string(rigidBody.bodyType == RigidBodyComponent::BodyType::Dynamic ? "Dynamic" : "Kinematic") +
|
|
|
|
|
". Please use Convex Hull collider instead, or set body type to Static. "
|
|
|
|
|
"Physics body will be removed until configuration is valid.");
|
|
|
|
|
|
|
|
|
|
// Remove existing body if any
|
|
|
|
|
if (rigidBody.bodyCreated) {
|
|
|
|
|
removeRigidBody(rigidBody);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mark as not created but not dirty (we don't want to retry every frame)
|
|
|
|
|
rigidBody.bodyCreated = false;
|
|
|
|
|
rigidBody.bodyDirty = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build collision shape
|
|
|
|
|
@@ -214,14 +297,21 @@ void EditorPhysicsSystem::updateRigidBody(flecs::entity entity,
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create body
|
|
|
|
|
// Create body at the current SceneNode position
|
|
|
|
|
// This ensures that when enabling a body, it starts at the current visual position
|
|
|
|
|
Ogre::Vector3 startPosition = transform.node ?
|
|
|
|
|
transform.node->_getDerivedPosition() : transform.position;
|
|
|
|
|
Ogre::Quaternion startRotation = transform.node ?
|
|
|
|
|
transform.node->_getDerivedOrientation() : transform.rotation;
|
|
|
|
|
|
|
|
|
|
// Create body or sensor
|
|
|
|
|
if (rigidBody.isSensor) {
|
|
|
|
|
rigidBody.bodyID = m_physics->createSensor(shape, transform.node,
|
|
|
|
|
rigidBody.bodyID = m_physics->createSensor(shape, startPosition, startRotation,
|
|
|
|
|
motionType, layer);
|
|
|
|
|
} else {
|
|
|
|
|
rigidBody.bodyID = m_physics->createBody(shape, rigidBody.mass,
|
|
|
|
|
transform.node,
|
|
|
|
|
motionType, layer);
|
|
|
|
|
startPosition, startRotation,
|
|
|
|
|
motionType, layer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rigidBody.bodyID.IsInvalid()) {
|
|
|
|
|
|