Can disable physics stepping
This commit is contained in:
@@ -103,7 +103,8 @@ bool EditorUISystem::onMousePressed(const Ogre::Ray &mouseRay)
|
||||
if (physics->raycastQuery(start, end, hitPos,
|
||||
hitBody)) {
|
||||
m_cursor3D->setPosition(hitPos);
|
||||
m_cursorPlaceMode = false; // disable after placement
|
||||
m_cursorPlaceMode =
|
||||
false; // disable after placement
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -337,13 +338,13 @@ void EditorUISystem::renderHierarchyWindow()
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
// Tools menu
|
||||
if (ImGui::BeginMenu("Tools")) {
|
||||
if (ImGui::MenuItem("3D Cursor")) {
|
||||
m_showCursorPanel = true;
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
// Tools menu
|
||||
if (ImGui::BeginMenu("Tools")) {
|
||||
if (ImGui::MenuItem("3D Cursor")) {
|
||||
m_showCursorPanel = true;
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
// Entity menu
|
||||
if (ImGui::BeginMenu("Entity")) {
|
||||
@@ -382,6 +383,23 @@ void EditorUISystem::renderHierarchyWindow()
|
||||
"When enabled, child entities' SceneNodes are parented to their parent's SceneNode, inheriting transforms. When disabled, SceneNodes are created at root level.");
|
||||
}
|
||||
|
||||
// Physics stepping toggle
|
||||
if (m_physicsSystem) {
|
||||
bool physicsEnabled =
|
||||
m_physicsSystem
|
||||
->isPhysicsEnabled();
|
||||
if (ImGui::Checkbox("Physics Stepping",
|
||||
&physicsEnabled)) {
|
||||
m_physicsSystem
|
||||
->setPhysicsEnabled(
|
||||
physicsEnabled);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Enable/disable physics simulation stepping. Disable to edit prefabs with physics (e.g. characters) without them falling or moving.");
|
||||
}
|
||||
}
|
||||
|
||||
// Physics debug draw toggle
|
||||
if (m_physicsSystem) {
|
||||
bool debugDraw =
|
||||
@@ -1552,8 +1570,7 @@ void EditorUISystem::showCreatePrefabDialog(flecs::entity entity)
|
||||
m_prefabNameBuffer[0] != '\0') {
|
||||
std::string prefabPath =
|
||||
PrefabSystem::getPrefabsDirectory() +
|
||||
"/" + m_prefabNameBuffer +
|
||||
".json";
|
||||
"/" + m_prefabNameBuffer + ".json";
|
||||
PrefabSystem prefabSys(m_world, m_sceneMgr);
|
||||
if (prefabSys.savePrefab(entity, prefabPath)) {
|
||||
// Convert source entity to prefab instance
|
||||
@@ -1583,10 +1600,9 @@ void EditorUISystem::renderPrefabBrowser()
|
||||
if (!m_showPrefabBrowser)
|
||||
return;
|
||||
|
||||
ImGui::SetNextWindowPos(
|
||||
ImVec2(LEFT_PANEL_WIDTH, 300), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(250, 400),
|
||||
ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImVec2(LEFT_PANEL_WIDTH, 300),
|
||||
ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(250, 400), ImGuiCond_FirstUseEver);
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse;
|
||||
if (ImGui::Begin("Prefab Browser", &m_showPrefabBrowser, flags)) {
|
||||
@@ -1603,7 +1619,8 @@ void EditorUISystem::renderPrefabBrowser()
|
||||
entry.path().extension() ==
|
||||
".json") {
|
||||
m_prefabFiles.push_back(
|
||||
entry.path().filename()
|
||||
entry.path()
|
||||
.filename()
|
||||
.string());
|
||||
}
|
||||
}
|
||||
@@ -1636,11 +1653,10 @@ void EditorUISystem::renderPrefabBrowser()
|
||||
|
||||
std::string editId = "Edit##" + file;
|
||||
if (ImGui::Button(editId.c_str())) {
|
||||
SceneSerializer serializer(m_world,
|
||||
m_sceneMgr);
|
||||
SceneSerializer serializer(m_world, m_sceneMgr);
|
||||
flecs::entity prefabRoot =
|
||||
serializer.loadPrefabForEdit(
|
||||
path, this);
|
||||
serializer.loadPrefabForEdit(path,
|
||||
this);
|
||||
if (prefabRoot.is_alive()) {
|
||||
setSelectedEntity(prefabRoot);
|
||||
}
|
||||
@@ -1649,10 +1665,8 @@ void EditorUISystem::renderPrefabBrowser()
|
||||
|
||||
std::string instId = "Inst##" + file;
|
||||
if (ImGui::Button(instId.c_str())) {
|
||||
PrefabSystem prefabSys(m_world,
|
||||
m_sceneMgr);
|
||||
flecs::entity parent =
|
||||
flecs::entity::null();
|
||||
PrefabSystem prefabSys(m_world, m_sceneMgr);
|
||||
flecs::entity parent = flecs::entity::null();
|
||||
Ogre::Vector3 pos(0, 0, 0);
|
||||
|
||||
if (m_prefabUseCursor && m_cursor3D &&
|
||||
@@ -1669,22 +1683,25 @@ void EditorUISystem::renderPrefabBrowser()
|
||||
->getPhysicsWrapper();
|
||||
if (physics) {
|
||||
Ogre::Vector3 start =
|
||||
pos + Ogre::Vector3(
|
||||
0,
|
||||
m_prefabRaycastMargin,
|
||||
0);
|
||||
pos +
|
||||
Ogre::Vector3(
|
||||
0,
|
||||
m_prefabRaycastMargin,
|
||||
0);
|
||||
Ogre::Vector3 end =
|
||||
pos + Ogre::Vector3(
|
||||
0,
|
||||
-1000.0f,
|
||||
0);
|
||||
pos +
|
||||
Ogre::Vector3(
|
||||
0,
|
||||
-1000.0f,
|
||||
0);
|
||||
Ogre::Vector3 hitPos;
|
||||
JPH::BodyID hitBody;
|
||||
if (physics->raycastQuery(
|
||||
start, end,
|
||||
hitPos,
|
||||
hitBody)) {
|
||||
pos = hitPos + Ogre::Vector3(
|
||||
pos = hitPos +
|
||||
Ogre::Vector3(
|
||||
0,
|
||||
m_prefabRaycastMargin,
|
||||
0);
|
||||
@@ -1695,8 +1712,8 @@ void EditorUISystem::renderPrefabBrowser()
|
||||
// If not at root, parent under selected entity
|
||||
if (!m_prefabInstAtRoot &&
|
||||
m_selectedEntity.is_alive() &&
|
||||
m_selectedEntity.has<
|
||||
TransformComponent>()) {
|
||||
m_selectedEntity
|
||||
.has<TransformComponent>()) {
|
||||
parent = m_selectedEntity;
|
||||
// Convert world pos to local
|
||||
auto &pt = m_selectedEntity.get<
|
||||
@@ -1708,8 +1725,8 @@ void EditorUISystem::renderPrefabBrowser()
|
||||
}
|
||||
} else if (!m_prefabInstAtRoot &&
|
||||
m_selectedEntity.is_alive() &&
|
||||
m_selectedEntity.has<
|
||||
TransformComponent>()) {
|
||||
m_selectedEntity
|
||||
.has<TransformComponent>()) {
|
||||
parent = m_selectedEntity;
|
||||
// Local offset from parent
|
||||
pos = Ogre::Vector3(2, 0, 0);
|
||||
@@ -1737,10 +1754,9 @@ void EditorUISystem::renderCursorPanel()
|
||||
if (!m_cursor3D)
|
||||
return;
|
||||
|
||||
ImGui::SetNextWindowPos(
|
||||
ImVec2(LEFT_PANEL_WIDTH, 100), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(280, 350),
|
||||
ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImVec2(LEFT_PANEL_WIDTH, 100),
|
||||
ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(280, 350), ImGuiCond_FirstUseEver);
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse;
|
||||
if (ImGui::Begin("3D Cursor", &m_showCursorPanel, flags)) {
|
||||
@@ -1767,8 +1783,8 @@ void EditorUISystem::renderCursorPanel()
|
||||
Ogre::Vector3 pos = m_cursor3D->getPosition();
|
||||
float posArr[3] = { pos.x, pos.y, pos.z };
|
||||
if (ImGui::DragFloat3("Position", posArr, 0.01f)) {
|
||||
m_cursor3D->setPosition(Ogre::Vector3(
|
||||
posArr[0], posArr[1], posArr[2]));
|
||||
m_cursor3D->setPosition(
|
||||
Ogre::Vector3(posArr[0], posArr[1], posArr[2]));
|
||||
}
|
||||
|
||||
// Rotation editor (Euler angles)
|
||||
@@ -1800,7 +1816,8 @@ void EditorUISystem::renderCursorPanel()
|
||||
if (m_selectedEntity.is_alive() &&
|
||||
m_selectedEntity.has<TransformComponent>()) {
|
||||
m_cursor3D->snapToTransform(
|
||||
m_selectedEntity.get<TransformComponent>());
|
||||
m_selectedEntity
|
||||
.get<TransformComponent>());
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
@@ -1815,12 +1832,14 @@ void EditorUISystem::renderCursorPanel()
|
||||
if (m_selectedEntity.is_alive() &&
|
||||
m_selectedEntity.has<TransformComponent>()) {
|
||||
auto &transform =
|
||||
m_selectedEntity.get_mut<TransformComponent>();
|
||||
m_selectedEntity
|
||||
.get_mut<TransformComponent>();
|
||||
m_cursor3D->applyToTransform(transform);
|
||||
if (m_selectedEntity.has<
|
||||
StaticGeometryMemberComponent>()) {
|
||||
m_selectedEntity.get_mut<
|
||||
StaticGeometryMemberComponent>()
|
||||
m_selectedEntity
|
||||
.get_mut<
|
||||
StaticGeometryMemberComponent>()
|
||||
.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
#include "../components/Transform.hpp"
|
||||
#include <OgreLogManager.h>
|
||||
|
||||
EditorPhysicsSystem::EditorPhysicsSystem(flecs::world& world,
|
||||
Ogre::SceneManager* sceneMgr)
|
||||
EditorPhysicsSystem::EditorPhysicsSystem(flecs::world &world,
|
||||
Ogre::SceneManager *sceneMgr)
|
||||
: m_world(world)
|
||||
, m_sceneMgr(sceneMgr)
|
||||
, m_rigidBodyQuery(world.query<RigidBodyComponent, TransformComponent>())
|
||||
, m_rigidBodyQuery(
|
||||
world.query<RigidBodyComponent, TransformComponent>())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -14,38 +15,47 @@ EditorPhysicsSystem::~EditorPhysicsSystem() = default;
|
||||
|
||||
void EditorPhysicsSystem::initialize()
|
||||
{
|
||||
if (m_initialized) return;
|
||||
if (m_initialized)
|
||||
return;
|
||||
|
||||
// Create physics wrapper
|
||||
Ogre::SceneNode* cameraNode = m_sceneMgr->getRootSceneNode()->createChildSceneNode("PhysicsCameraNode");
|
||||
m_physics = std::make_unique<JoltPhysicsWrapper>(m_sceneMgr, cameraNode);
|
||||
|
||||
Ogre::SceneNode *cameraNode =
|
||||
m_sceneMgr->getRootSceneNode()->createChildSceneNode(
|
||||
"PhysicsCameraNode");
|
||||
m_physics =
|
||||
std::make_unique<JoltPhysicsWrapper>(m_sceneMgr, cameraNode);
|
||||
|
||||
m_initialized = true;
|
||||
Ogre::LogManager::getSingleton().logMessage("Physics system initialized");
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Physics system initialized");
|
||||
}
|
||||
|
||||
void EditorPhysicsSystem::update(float deltaTime)
|
||||
{
|
||||
if (!m_initialized || !m_physics) return;
|
||||
if (!m_initialized || !m_physics)
|
||||
return;
|
||||
|
||||
// Sync bodies before simulation
|
||||
syncBodies();
|
||||
|
||||
// Step physics
|
||||
m_physics->update(deltaTime);
|
||||
|
||||
// Step physics (skip if physics stepping is disabled)
|
||||
if (m_physicsEnabled) {
|
||||
m_physics->update(deltaTime);
|
||||
}
|
||||
|
||||
// Update SceneNodes from physics for dynamic bodies
|
||||
updateDynamicBodies();
|
||||
}
|
||||
|
||||
void EditorPhysicsSystem::syncBodies()
|
||||
{
|
||||
if (!m_initialized || !m_physics) return;
|
||||
if (!m_initialized || !m_physics)
|
||||
return;
|
||||
|
||||
// Process all rigid bodies
|
||||
m_rigidBodyQuery.each([&](flecs::entity entity,
|
||||
RigidBodyComponent& rigidBody,
|
||||
TransformComponent& transform) {
|
||||
RigidBodyComponent &rigidBody,
|
||||
TransformComponent &transform) {
|
||||
// Handle enabled/disabled state
|
||||
if (!rigidBody.enabled) {
|
||||
// Body is disabled - remove from physics if it exists
|
||||
@@ -54,7 +64,7 @@ void EditorPhysicsSystem::syncBodies()
|
||||
}
|
||||
return; // Skip rest of processing for disabled bodies
|
||||
}
|
||||
|
||||
|
||||
// Body is enabled
|
||||
if (rigidBody.bodyDirty || !rigidBody.bodyCreated) {
|
||||
// Create or recreate the body
|
||||
@@ -63,30 +73,30 @@ void EditorPhysicsSystem::syncBodies()
|
||||
} 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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -94,24 +104,29 @@ void EditorPhysicsSystem::syncBodies()
|
||||
|
||||
void EditorPhysicsSystem::updateDynamicBodies()
|
||||
{
|
||||
if (!m_initialized || !m_physics) return;
|
||||
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)
|
||||
RigidBodyComponent &rigidBody,
|
||||
TransformComponent &transform) {
|
||||
if (!rigidBody.enabled || !rigidBody.bodyCreated ||
|
||||
!transform.node)
|
||||
return;
|
||||
|
||||
if (rigidBody.bodyType == RigidBodyComponent::BodyType::Dynamic) {
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
@@ -119,7 +134,8 @@ void EditorPhysicsSystem::updateDynamicBodies()
|
||||
});
|
||||
}
|
||||
|
||||
JPH::ShapeRefC EditorPhysicsSystem::createShape(PhysicsColliderComponent& collider)
|
||||
JPH::ShapeRefC
|
||||
EditorPhysicsSystem::createShape(PhysicsColliderComponent &collider)
|
||||
{
|
||||
if (!collider.shapeDirty && collider.shape) {
|
||||
return collider.shape;
|
||||
@@ -138,29 +154,33 @@ JPH::ShapeRefC EditorPhysicsSystem::createShape(PhysicsColliderComponent& collid
|
||||
}
|
||||
case PhysicsColliderComponent::ShapeType::Capsule: {
|
||||
result = m_physics->createCapsuleShape(collider.halfHeight,
|
||||
collider.radius);
|
||||
collider.radius);
|
||||
break;
|
||||
}
|
||||
case PhysicsColliderComponent::ShapeType::Cylinder: {
|
||||
result = m_physics->createCylinderShape(collider.halfHeight,
|
||||
collider.radius);
|
||||
collider.radius);
|
||||
break;
|
||||
}
|
||||
case PhysicsColliderComponent::ShapeType::Mesh: {
|
||||
if (!collider.meshName.empty()) {
|
||||
try {
|
||||
result = m_physics->createMeshShape(collider.meshName);
|
||||
result = m_physics->createMeshShape(
|
||||
collider.meshName);
|
||||
if (!result) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Mesh shape creation returned null for: " + collider.meshName);
|
||||
"Mesh shape creation returned null for: " +
|
||||
collider.meshName);
|
||||
}
|
||||
} catch (const Ogre::Exception& e) {
|
||||
} catch (const Ogre::Exception &e) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Exception creating mesh shape: " + collider.meshName +
|
||||
" - " + e.getDescription());
|
||||
"Exception creating mesh shape: " +
|
||||
collider.meshName + " - " +
|
||||
e.getDescription());
|
||||
} catch (...) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Unknown exception creating mesh shape: " + collider.meshName);
|
||||
"Unknown exception creating mesh shape: " +
|
||||
collider.meshName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -168,7 +188,8 @@ JPH::ShapeRefC EditorPhysicsSystem::createShape(PhysicsColliderComponent& collid
|
||||
case PhysicsColliderComponent::ShapeType::ConvexHull: {
|
||||
if (!collider.meshName.empty()) {
|
||||
try {
|
||||
result = m_physics->createConvexHullShape(collider.meshName);
|
||||
result = m_physics->createConvexHullShape(
|
||||
collider.meshName);
|
||||
} catch (...) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Failed to create convex hull shape: " +
|
||||
@@ -181,7 +202,8 @@ JPH::ShapeRefC EditorPhysicsSystem::createShape(PhysicsColliderComponent& collid
|
||||
|
||||
// If no shape created, default to a small box
|
||||
if (!result) {
|
||||
result = m_physics->createBoxShape(Ogre::Vector3(0.1f, 0.1f, 0.1f));
|
||||
result = m_physics->createBoxShape(
|
||||
Ogre::Vector3(0.1f, 0.1f, 0.1f));
|
||||
}
|
||||
|
||||
// Apply offset if any
|
||||
@@ -196,7 +218,8 @@ JPH::ShapeRefC EditorPhysicsSystem::createShape(PhysicsColliderComponent& collid
|
||||
return result;
|
||||
}
|
||||
|
||||
JPH::ShapeRefC EditorPhysicsSystem::buildCompoundShape(flecs::entity rigidBodyEntity)
|
||||
JPH::ShapeRefC
|
||||
EditorPhysicsSystem::buildCompoundShape(flecs::entity rigidBodyEntity)
|
||||
{
|
||||
std::vector<JPH::ShapeRefC> shapes;
|
||||
std::vector<Ogre::Vector3> positions;
|
||||
@@ -205,8 +228,9 @@ JPH::ShapeRefC EditorPhysicsSystem::buildCompoundShape(flecs::entity rigidBodyEn
|
||||
// Check if the rigid body entity itself has a collider
|
||||
if (rigidBodyEntity.has<PhysicsColliderComponent>() &&
|
||||
rigidBodyEntity.has<TransformComponent>()) {
|
||||
auto& collider = rigidBodyEntity.get_mut<PhysicsColliderComponent>();
|
||||
auto& transform = rigidBodyEntity.get<TransformComponent>();
|
||||
auto &collider =
|
||||
rigidBodyEntity.get_mut<PhysicsColliderComponent>();
|
||||
auto &transform = rigidBodyEntity.get<TransformComponent>();
|
||||
JPH::ShapeRefC shape = createShape(collider);
|
||||
if (shape) {
|
||||
shapes.push_back(shape);
|
||||
@@ -219,8 +243,9 @@ JPH::ShapeRefC EditorPhysicsSystem::buildCompoundShape(flecs::entity rigidBodyEn
|
||||
rigidBodyEntity.children([&](flecs::entity child) {
|
||||
if (child.has<PhysicsColliderComponent>() &&
|
||||
child.has<TransformComponent>()) {
|
||||
auto& collider = child.get_mut<PhysicsColliderComponent>();
|
||||
auto& transform = child.get<TransformComponent>();
|
||||
auto &collider =
|
||||
child.get_mut<PhysicsColliderComponent>();
|
||||
auto &transform = child.get<TransformComponent>();
|
||||
|
||||
JPH::ShapeRefC shape = createShape(collider);
|
||||
if (shape) {
|
||||
@@ -233,23 +258,24 @@ JPH::ShapeRefC EditorPhysicsSystem::buildCompoundShape(flecs::entity rigidBodyEn
|
||||
|
||||
if (shapes.empty()) {
|
||||
// No colliders, use default box
|
||||
return m_physics->createBoxShape(Ogre::Vector3(0.5f, 0.5f, 0.5f));
|
||||
return m_physics->createBoxShape(
|
||||
Ogre::Vector3(0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
|
||||
if (shapes.size() == 1) {
|
||||
// Single shape - use rotated translated shape
|
||||
return m_physics->createRotatedTranslatedShape(positions[0],
|
||||
rotations[0],
|
||||
shapes[0]);
|
||||
return m_physics->createRotatedTranslatedShape(
|
||||
positions[0], rotations[0], shapes[0]);
|
||||
}
|
||||
|
||||
// Multiple shapes - create static compound
|
||||
return m_physics->createStaticCompoundShape(shapes, positions, rotations);
|
||||
return m_physics->createStaticCompoundShape(shapes, positions,
|
||||
rotations);
|
||||
}
|
||||
|
||||
void EditorPhysicsSystem::updateRigidBody(flecs::entity entity,
|
||||
RigidBodyComponent& rigidBody,
|
||||
TransformComponent& transform)
|
||||
RigidBodyComponent &rigidBody,
|
||||
TransformComponent &transform)
|
||||
{
|
||||
// Remove existing body if any
|
||||
if (rigidBody.bodyCreated) {
|
||||
@@ -259,35 +285,43 @@ void EditorPhysicsSystem::updateRigidBody(flecs::entity entity,
|
||||
// Check for mesh colliders - they only work with Static bodies
|
||||
bool hasMeshCollider = false;
|
||||
if (entity.has<PhysicsColliderComponent>()) {
|
||||
auto& collider = entity.get<PhysicsColliderComponent>();
|
||||
if (collider.shapeType == PhysicsColliderComponent::ShapeType::Mesh) {
|
||||
auto &collider = entity.get<PhysicsColliderComponent>();
|
||||
if (collider.shapeType ==
|
||||
PhysicsColliderComponent::ShapeType::Mesh) {
|
||||
hasMeshCollider = true;
|
||||
}
|
||||
}
|
||||
if (!hasMeshCollider) {
|
||||
entity.children([&](flecs::entity child) {
|
||||
if (child.has<PhysicsColliderComponent>()) {
|
||||
auto& collider = child.get<PhysicsColliderComponent>();
|
||||
if (collider.shapeType == PhysicsColliderComponent::ShapeType::Mesh) {
|
||||
auto &collider =
|
||||
child.get<PhysicsColliderComponent>();
|
||||
if (collider.shapeType ==
|
||||
PhysicsColliderComponent::ShapeType::Mesh) {
|
||||
hasMeshCollider = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (hasMeshCollider && rigidBody.bodyType != RigidBodyComponent::BodyType::Static) {
|
||||
|
||||
if (hasMeshCollider &&
|
||||
rigidBody.bodyType != RigidBodyComponent::BodyType::Static) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"ERROR: Mesh colliders can only be used with Static bodies. "
|
||||
"Body type is " +
|
||||
std::string(rigidBody.bodyType == RigidBodyComponent::BodyType::Dynamic ? "Dynamic" : "Kinematic") +
|
||||
"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;
|
||||
@@ -296,7 +330,8 @@ void EditorPhysicsSystem::updateRigidBody(flecs::entity entity,
|
||||
|
||||
// Build collision shape
|
||||
JPH::ShapeRefC shape = buildCompoundShape(entity);
|
||||
if (!shape) return;
|
||||
if (!shape)
|
||||
return;
|
||||
|
||||
// Determine motion type and layer
|
||||
JPH::EMotionType motionType;
|
||||
@@ -320,22 +355,24 @@ void EditorPhysicsSystem::updateRigidBody(flecs::entity entity,
|
||||
|
||||
// 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;
|
||||
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, startPosition, startRotation,
|
||||
motionType, layer);
|
||||
rigidBody.bodyID = m_physics->createSensor(
|
||||
shape, startPosition, startRotation, motionType, layer);
|
||||
} else {
|
||||
rigidBody.bodyID = m_physics->createBody(shape, rigidBody.mass,
|
||||
startPosition, startRotation,
|
||||
motionType, layer);
|
||||
startPosition,
|
||||
startRotation,
|
||||
motionType, layer);
|
||||
}
|
||||
|
||||
|
||||
if (rigidBody.bodyID.IsInvalid()) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Failed to create rigid body");
|
||||
@@ -344,7 +381,7 @@ void EditorPhysicsSystem::updateRigidBody(flecs::entity entity,
|
||||
|
||||
// Set properties
|
||||
m_physics->setFriction(rigidBody.bodyID, rigidBody.friction);
|
||||
|
||||
|
||||
// Add to physics world
|
||||
m_physics->addBody(rigidBody.bodyID, JPH::EActivation::Activate);
|
||||
|
||||
@@ -354,9 +391,10 @@ void EditorPhysicsSystem::updateRigidBody(flecs::entity entity,
|
||||
Ogre::LogManager::getSingleton().logMessage("Rigid body created");
|
||||
}
|
||||
|
||||
void EditorPhysicsSystem::removeRigidBody(RigidBodyComponent& rigidBody)
|
||||
void EditorPhysicsSystem::removeRigidBody(RigidBodyComponent &rigidBody)
|
||||
{
|
||||
if (!rigidBody.bodyCreated || rigidBody.bodyID.IsInvalid()) return;
|
||||
if (!rigidBody.bodyCreated || rigidBody.bodyID.IsInvalid())
|
||||
return;
|
||||
|
||||
m_physics->removeBody(rigidBody.bodyID);
|
||||
m_physics->destroyBody(rigidBody.bodyID);
|
||||
|
||||
@@ -30,6 +30,16 @@ public:
|
||||
// Update SceneNodes from physics for dynamic bodies
|
||||
void updateDynamicBodies();
|
||||
|
||||
// Enable/disable physics stepping
|
||||
void setPhysicsEnabled(bool enable)
|
||||
{
|
||||
m_physicsEnabled = enable;
|
||||
}
|
||||
bool isPhysicsEnabled() const
|
||||
{
|
||||
return m_physicsEnabled;
|
||||
}
|
||||
|
||||
// Enable/disable debug drawing
|
||||
void setDebugDraw(bool enable);
|
||||
bool isDebugDrawEnabled() const
|
||||
@@ -69,6 +79,7 @@ private:
|
||||
std::unique_ptr<JoltPhysicsWrapper> m_physics;
|
||||
bool m_initialized = false;
|
||||
bool m_debugDraw = false;
|
||||
bool m_physicsEnabled = true;
|
||||
|
||||
// Query for entities with RigidBody
|
||||
flecs::query<RigidBodyComponent, TransformComponent> m_rigidBodyQuery;
|
||||
|
||||
Reference in New Issue
Block a user