Static body check

This commit is contained in:
2026-04-03 21:12:45 +03:00
parent 2a2fd53c4f
commit ebd875feac
5 changed files with 120 additions and 9 deletions

View File

@@ -29,6 +29,9 @@ struct RigidBodyComponent {
float restitution = 0.0f; // Bounciness
bool isSensor = false; // Detects collisions but doesn't respond
// Enable/disable physics body
bool enabled = true; // If false, body is removed from physics world
// The Jolt body ID
JPH::BodyID bodyID;
bool bodyCreated = false;

View File

@@ -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()) {

View File

@@ -26,6 +26,9 @@ public:
// Process component changes and create/update bodies
void syncBodies();
// Update SceneNodes from physics for dynamic bodies
void updateDynamicBodies();
// Enable/disable debug drawing
void setDebugDraw(bool enable);

View File

@@ -271,6 +271,7 @@ nlohmann::json SceneSerializer::serializeRigidBody(flecs::entity entity)
json["friction"] = rb.friction;
json["restitution"] = rb.restitution;
json["isSensor"] = rb.isSensor;
json["enabled"] = rb.enabled;
return json;
}
@@ -510,6 +511,7 @@ void SceneSerializer::deserializeRigidBody(flecs::entity entity, const nlohmann:
rb.friction = json.value("friction", 0.5f);
rb.restitution = json.value("restitution", 0.0f);
rb.isSensor = json.value("isSensor", false);
rb.enabled = json.value("enabled", true);
// Mark as dirty so physics system will create the body
rb.bodyDirty = true;

View File

@@ -10,6 +10,19 @@ bool RigidBodyEditor::renderComponent(flecs::entity entity,
ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Indent();
// Enabled checkbox - controls if body is in physics world
if (ImGui::Checkbox("Enabled", &rigidBody.enabled)) {
rigidBody.markDirty();
modified = true;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip(
"If unchecked, the body is removed from the physics world. "
"When checked again, it will be re-added at the current position.");
}
ImGui::Separator();
// Body type selector
const char *bodyTypes[] = { "Static", "Dynamic", "Kinematic" };
int currentType = static_cast<int>(rigidBody.bodyType);