Now repeated smart object action works perfectly
This commit is contained in:
@@ -309,8 +309,15 @@ void EditorApp::setup()
|
||||
m_animationTreeSystem = std::make_unique<AnimationTreeSystem>(
|
||||
m_world, m_sceneMgr);
|
||||
m_animationTreeSystem->initialize();
|
||||
|
||||
// Setup Character physics system (needed by BehaviorTreeSystem)
|
||||
m_characterSystem =
|
||||
std::make_unique<CharacterSystem>(m_world, m_sceneMgr);
|
||||
m_characterSystem->initialize();
|
||||
|
||||
m_behaviorTreeSystem = std::make_unique<BehaviorTreeSystem>(
|
||||
m_world, m_sceneMgr, m_animationTreeSystem.get());
|
||||
m_world, m_sceneMgr, m_animationTreeSystem.get(),
|
||||
m_characterSystem.get());
|
||||
|
||||
// Setup NavMesh system
|
||||
m_navMeshSystem =
|
||||
@@ -324,12 +331,6 @@ void EditorApp::setup()
|
||||
m_smartObjectSystem->setAnimationTreeSystem(
|
||||
m_animationTreeSystem.get());
|
||||
|
||||
// Setup Character physics system
|
||||
|
||||
m_characterSystem =
|
||||
std::make_unique<CharacterSystem>(m_world, m_sceneMgr);
|
||||
m_characterSystem->initialize();
|
||||
|
||||
// Setup CellGrid system
|
||||
m_cellGridSystem =
|
||||
std::make_unique<CellGridSystem>(m_world, m_sceneMgr);
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
* name = child entity name to teleport to.
|
||||
* The character is positioned at the child's absolute
|
||||
* world transform (position + orientation).
|
||||
* "disablePhysics" - Leaf: removes character's JPH::BodyID from physics
|
||||
* system so physics no longer interferes with animation.
|
||||
* "enablePhysics" - Leaf: re-adds character's JPH::BodyID to physics
|
||||
* system to restore physics simulation.
|
||||
*/
|
||||
struct BehaviorTreeNode {
|
||||
Ogre::String type = "task";
|
||||
@@ -68,7 +72,8 @@ struct BehaviorTreeNode {
|
||||
type == "isAnimationEnded" || type == "setBit" ||
|
||||
type == "checkBit" || type == "setValue" ||
|
||||
type == "checkValue" || type == "blackboardDump" ||
|
||||
type == "delay" || type == "teleportToChild";
|
||||
type == "delay" || type == "teleportToChild" ||
|
||||
type == "disablePhysics" || type == "enablePhysics";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,13 @@ struct CharacterComponent {
|
||||
/* Enable/disable physics character */
|
||||
bool enabled = true;
|
||||
|
||||
/* Physics was explicitly disabled (e.g. by behavior tree node).
|
||||
* When true, the character's JPH::BodyID is removed from the physics
|
||||
* system but the JPH::Character object is kept alive so it can be
|
||||
* re-added later. This is separate from 'enabled' which controls
|
||||
* whether the character system processes this entity at all. */
|
||||
bool physicsDisabled = false;
|
||||
|
||||
/* Dirty flag — triggers rebuild of the Jolt character */
|
||||
bool dirty = true;
|
||||
|
||||
@@ -35,8 +42,14 @@ struct CharacterComponent {
|
||||
float floorCheckDistance = 2.0f;
|
||||
bool useGravity = true;
|
||||
|
||||
float getHalfHeight() const { return height * 0.5f; }
|
||||
float getTotalHeight() const { return height + 2.0f * radius; }
|
||||
float getHalfHeight() const
|
||||
{
|
||||
return height * 0.5f;
|
||||
}
|
||||
float getTotalHeight() const
|
||||
{
|
||||
return height + 2.0f * radius;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EDITSCENE_CHARACTER_HPP
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "BehaviorTreeSystem.hpp"
|
||||
#include "AnimationTreeSystem.hpp"
|
||||
#include "CharacterSystem.hpp"
|
||||
#include "SmartObjectSystem.hpp"
|
||||
#include "../components/BehaviorTree.hpp"
|
||||
#include "../components/ActionDatabase.hpp"
|
||||
@@ -8,6 +9,7 @@
|
||||
#include "../components/Transform.hpp"
|
||||
#include "../components/EntityName.hpp"
|
||||
#include "../components/Relationship.hpp"
|
||||
#include "../components/Character.hpp"
|
||||
#include <OgreLogManager.h>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
@@ -159,10 +161,12 @@ static bool compareValues(const Comparison &cmp, int actualInt,
|
||||
|
||||
BehaviorTreeSystem::BehaviorTreeSystem(flecs::world &world,
|
||||
Ogre::SceneManager *sceneMgr,
|
||||
AnimationTreeSystem *animSystem)
|
||||
AnimationTreeSystem *animSystem,
|
||||
CharacterSystem *charSystem)
|
||||
: m_world(world)
|
||||
, m_sceneMgr(sceneMgr)
|
||||
, m_animSystem(animSystem)
|
||||
, m_charSystem(charSystem)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -458,6 +462,25 @@ BehaviorTreeSystem::evaluateNode(const BehaviorTreeNode &node, flecs::entity e,
|
||||
return Status::success;
|
||||
}
|
||||
|
||||
/* --- Character physics disable/enable nodes --- */
|
||||
if (node.type == "disablePhysics") {
|
||||
if (isNewlyActive(state, &node) && m_charSystem) {
|
||||
m_charSystem->disablePhysics(e);
|
||||
std::cout << "[BT] disablePhysics: entity=" << e.id()
|
||||
<< std::endl;
|
||||
}
|
||||
return Status::success;
|
||||
}
|
||||
|
||||
if (node.type == "enablePhysics") {
|
||||
if (isNewlyActive(state, &node) && m_charSystem) {
|
||||
m_charSystem->enablePhysics(e);
|
||||
std::cout << "[BT] enablePhysics: entity=" << e.id()
|
||||
<< std::endl;
|
||||
}
|
||||
return Status::success;
|
||||
}
|
||||
|
||||
/* --- Teleport to Smart Object child node --- */
|
||||
if (node.type == "teleportToChild") {
|
||||
if (isNewlyActive(state, &node)) {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "../components/ActionDebug.hpp"
|
||||
|
||||
class AnimationTreeSystem;
|
||||
class CharacterSystem;
|
||||
|
||||
/**
|
||||
* Evaluates data-driven BehaviorTreeComponent each frame.
|
||||
@@ -23,7 +24,8 @@ class AnimationTreeSystem;
|
||||
class BehaviorTreeSystem {
|
||||
public:
|
||||
BehaviorTreeSystem(flecs::world &world, Ogre::SceneManager *sceneMgr,
|
||||
AnimationTreeSystem *animSystem);
|
||||
AnimationTreeSystem *animSystem,
|
||||
CharacterSystem *charSystem = nullptr);
|
||||
~BehaviorTreeSystem();
|
||||
|
||||
void update(float deltaTime);
|
||||
@@ -78,6 +80,7 @@ private:
|
||||
flecs::world &m_world;
|
||||
Ogre::SceneManager *m_sceneMgr;
|
||||
AnimationTreeSystem *m_animSystem;
|
||||
CharacterSystem *m_charSystem;
|
||||
|
||||
std::unordered_map<flecs::entity_t, RunnerState> m_runnerStates;
|
||||
std::unordered_map<flecs::entity_t, RunnerState> m_actionDebugStates;
|
||||
|
||||
@@ -191,6 +191,54 @@ void CharacterSystem::teardownEntity(flecs::entity e)
|
||||
m_states.erase(it);
|
||||
}
|
||||
|
||||
void CharacterSystem::disablePhysics(flecs::entity e)
|
||||
{
|
||||
if (!m_physics)
|
||||
return;
|
||||
|
||||
auto it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
|
||||
CharacterState &state = it->second;
|
||||
if (!state.character)
|
||||
return;
|
||||
|
||||
JPH::BodyID bodyID = state.character->GetBodyID();
|
||||
if (m_physics->isAdded(bodyID)) {
|
||||
state.character->RemoveFromPhysicsSystem();
|
||||
}
|
||||
|
||||
if (e.has<CharacterComponent>()) {
|
||||
auto &cc = e.get_mut<CharacterComponent>();
|
||||
cc.physicsDisabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterSystem::enablePhysics(flecs::entity e)
|
||||
{
|
||||
if (!m_physics)
|
||||
return;
|
||||
|
||||
auto it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
|
||||
CharacterState &state = it->second;
|
||||
if (!state.character)
|
||||
return;
|
||||
|
||||
JPH::BodyID bodyID = state.character->GetBodyID();
|
||||
if (!m_physics->isAdded(bodyID)) {
|
||||
state.character->AddToPhysicsSystem();
|
||||
}
|
||||
|
||||
if (e.has<CharacterComponent>()) {
|
||||
auto &cc = e.get_mut<CharacterComponent>();
|
||||
cc.physicsDisabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterSystem::update(float deltaTime)
|
||||
{
|
||||
if (!m_initialized || !m_physics)
|
||||
@@ -217,6 +265,10 @@ void CharacterSystem::update(float deltaTime)
|
||||
if (!state.character || !state.sceneNode)
|
||||
return;
|
||||
|
||||
/* Skip physics processing when physics is disabled */
|
||||
if (cc.physicsDisabled)
|
||||
return;
|
||||
|
||||
/* Read current physics position */
|
||||
Ogre::Vector3 charPos = JoltPhysics::convert(
|
||||
state.character->GetPosition());
|
||||
@@ -235,7 +287,8 @@ void CharacterSystem::update(float deltaTime)
|
||||
* Preserve physics-driven Y velocity when no explicit
|
||||
* vertical input is given so gravity/buoyancy/jumps
|
||||
* are not overwritten every frame. */
|
||||
JPH::Vec3 currentVel = state.character->GetLinearVelocity();
|
||||
JPH::Vec3 currentVel =
|
||||
state.character->GetLinearVelocity();
|
||||
JPH::Vec3 desiredVel = JoltPhysics::convert<JPH::Vec3>(
|
||||
cc.linearVelocity);
|
||||
JPH::Vec3 finalVel;
|
||||
|
||||
@@ -28,6 +28,21 @@ public:
|
||||
void initialize();
|
||||
void update(float deltaTime);
|
||||
|
||||
/**
|
||||
* Disable physics for a character entity.
|
||||
* Removes the JPH::Character's BodyID from the physics system
|
||||
* but keeps the JPH::Character object alive so it can be re-added later.
|
||||
* Sets CharacterComponent::physicsDisabled = true.
|
||||
*/
|
||||
void disablePhysics(flecs::entity e);
|
||||
|
||||
/**
|
||||
* Enable physics for a character entity.
|
||||
* Re-adds the JPH::Character's BodyID to the physics system.
|
||||
* Sets CharacterComponent::physicsDisabled = false.
|
||||
*/
|
||||
void enablePhysics(flecs::entity e);
|
||||
|
||||
private:
|
||||
struct CharacterState {
|
||||
JPH::Character *character = nullptr;
|
||||
|
||||
@@ -915,21 +915,40 @@ void SmartObjectSystem::update(float deltaTime)
|
||||
// Kick off the action's
|
||||
// behavior tree via
|
||||
// BehaviorTreeSystem's
|
||||
// ActionDebug path
|
||||
// ActionDebug path.
|
||||
// Only reset runTimer on the
|
||||
// first frame of execution
|
||||
// (when isRunning is false) so
|
||||
// BehaviorTreeSystem re-initializes
|
||||
// the runner state for a fresh
|
||||
// execution. Do NOT reset every
|
||||
// frame or isNewlyActive will
|
||||
// fire repeatedly.
|
||||
if (!debug.isRunning) {
|
||||
debug.runTimer = 0.0f;
|
||||
}
|
||||
debug.isRunning = true;
|
||||
debug.currentActionName =
|
||||
state.target.actionName;
|
||||
|
||||
// Check if the behavior tree
|
||||
// has finished (sequence
|
||||
// completed or failed)
|
||||
// completed or failed).
|
||||
// Only check completion when
|
||||
// runTimer > 0 (at least one
|
||||
// frame has passed since
|
||||
// starting) to avoid
|
||||
// immediately detecting
|
||||
// completion on the same frame
|
||||
// the tree was started.
|
||||
auto &btState =
|
||||
m_btSystem
|
||||
->getActionDebugState(
|
||||
e.id());
|
||||
if (btState.treeResult !=
|
||||
BehaviorTreeSystem::Status::
|
||||
running) {
|
||||
if (debug.runTimer > 0.0f &&
|
||||
btState.treeResult !=
|
||||
BehaviorTreeSystem::
|
||||
Status::running) {
|
||||
// Behavior tree
|
||||
// completed - stop
|
||||
// evaluation
|
||||
|
||||
@@ -23,6 +23,10 @@ static ImU32 nodeTypeColorU32(const Ogre::String &type)
|
||||
return IM_COL32(0xFF, 0xD7, 0x00, 0xFF);
|
||||
if (type == "teleportToChild")
|
||||
return IM_COL32(0xFF, 0x69, 0xB4, 0xFF);
|
||||
if (type == "disablePhysics")
|
||||
return IM_COL32(0x80, 0x80, 0x80, 0xFF);
|
||||
if (type == "enablePhysics")
|
||||
return IM_COL32(0x4C, 0xCC, 0x4C, 0xFF);
|
||||
return IM_COL32(0xFF, 0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
|
||||
@@ -196,6 +200,10 @@ void BehaviorTreeEditor::renderTree(BehaviorTreeNode &node,
|
||||
queueAddChild(&node, "delay");
|
||||
if (ImGui::MenuItem("Add Teleport To Child"))
|
||||
queueAddChild(&node, "teleportToChild");
|
||||
if (ImGui::MenuItem("Add Disable Physics"))
|
||||
queueAddChild(&node, "disablePhysics");
|
||||
if (ImGui::MenuItem("Add Enable Physics"))
|
||||
queueAddChild(&node, "enablePhysics");
|
||||
}
|
||||
if (parent) {
|
||||
size_t idx = findChildIndex(*parent, &node);
|
||||
@@ -245,6 +253,10 @@ void BehaviorTreeEditor::renderTree(BehaviorTreeNode &node,
|
||||
queueAddChild(&node, "delay");
|
||||
if (ImGui::MenuItem("Teleport To Child"))
|
||||
queueAddChild(&node, "teleportToChild");
|
||||
if (ImGui::MenuItem("Disable Physics"))
|
||||
queueAddChild(&node, "disablePhysics");
|
||||
if (ImGui::MenuItem("Enable Physics"))
|
||||
queueAddChild(&node, "enablePhysics");
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
@@ -296,7 +308,9 @@ void BehaviorTreeEditor::renderProperties(BehaviorTreeNode *node)
|
||||
"checkValue",
|
||||
"blackboardDump",
|
||||
"delay",
|
||||
"teleportToChild" };
|
||||
"teleportToChild",
|
||||
"disablePhysics",
|
||||
"enablePhysics" };
|
||||
int typeIdx = 0;
|
||||
for (int i = 0; i < IM_ARRAYSIZE(types); i++) {
|
||||
if (node->type == types[i]) {
|
||||
|
||||
@@ -92,6 +92,10 @@ static ImVec4 typeColorVec(const char *type)
|
||||
return ImVec4(1.0f, 0.84f, 0.0f, 1.0f);
|
||||
if (!strcmp(type, "teleportToChild"))
|
||||
return ImVec4(1.0f, 0.41f, 0.71f, 1.0f);
|
||||
if (!strcmp(type, "disablePhysics"))
|
||||
return ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
if (!strcmp(type, "enablePhysics"))
|
||||
return ImVec4(0.3f, 0.8f, 0.3f, 1.0f);
|
||||
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
@@ -254,7 +258,9 @@ void InlineBehaviorTreeEditor::renderProps(BehaviorTreeNode *node)
|
||||
"checkValue",
|
||||
"blackboardDump",
|
||||
"delay",
|
||||
"teleportToChild" };
|
||||
"teleportToChild",
|
||||
"disablePhysics",
|
||||
"enablePhysics" };
|
||||
int current = 0;
|
||||
for (int i = 0; i < IM_ARRAYSIZE(types); i++) {
|
||||
if (node->type == types[i]) {
|
||||
|
||||
Reference in New Issue
Block a user