Can disable physics stepping

This commit is contained in:
2026-04-26 22:15:15 +03:00
parent 7563937ab8
commit a75db85027
3 changed files with 209 additions and 141 deletions

View File

@@ -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();
}
}

View File

@@ -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);

View File

@@ -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;