Smart objects work!

This commit is contained in:
2026-04-25 09:04:12 +03:00
parent 2e358275f0
commit 3bd2801d1d

View File

@@ -346,6 +346,9 @@ void SmartObjectSystem::update(float deltaTime)
auto &soComp =
state.target.smartObject
.get<SmartObjectComponent>();
// Always check range first - if we're close enough,
// execute the action regardless of path state
if (isInRange(charPos, objPos, soComp.radius,
soComp.height)) {
state.state = State::Executing;
@@ -376,8 +379,45 @@ void SmartObjectSystem::update(float deltaTime)
}
}
// Check if path is exhausted
if (state.target.pathIndex >=
(int)state.target.path.size()) {
float distToObj =
charPos.distance(objPos);
// If we're close enough to the object
// (within radius*2), teleport to range
// and execute
if (distToObj < soComp.radius * 2.0f) {
// Teleport character to be
// within range
Ogre::Vector3 dirToObj =
objPos - charPos;
dirToObj.y = 0;
float xzDist =
dirToObj.length();
if (xzDist > 0.01f) {
dirToObj /= xzDist;
Ogre::Vector3 newPos =
objPos -
dirToObj *
(soComp.radius *
0.5f);
newPos.y = charPos.y;
if (trans.node) {
trans.node->setPosition(
newPos);
}
trans.position = newPos;
}
state.state = State::Executing;
state.target.isExecuting = true;
state.target.executionTimer =
0.0f;
cc.linearVelocity =
Ogre::Vector3::ZERO;
return;
}
// Too far - recalculate path
state.target.path.clear();
state.target.path.push_back(objPos);
state.target.pathIndex = 0;
@@ -388,12 +428,45 @@ void SmartObjectSystem::update(float deltaTime)
.path[state.target.pathIndex];
Ogre::Vector3 toTarget = targetPos - charPos;
if (toTarget.length() < 0.5f) {
// Waypoint arrival threshold - use generous
// value since waypoints are just guide points
const float WAYPOINT_THRESHOLD = 1.0f;
if (toTarget.length() < WAYPOINT_THRESHOLD) {
state.target.pathIndex++;
if (state.target.pathIndex >=
(int)state.target.path.size()) {
toTarget = objPos - charPos;
if (toTarget.length() < 0.5f) {
// Path exhausted - teleport to
// range and execute if close
// enough
float distToObj =
charPos.distance(
objPos);
if (distToObj <
soComp.radius * 2.0f) {
Ogre::Vector3 dirToObj =
objPos -
charPos;
dirToObj.y = 0;
float xzDist =
dirToObj.length();
if (xzDist > 0.01f) {
dirToObj /=
xzDist;
Ogre::Vector3 newPos =
objPos -
dirToObj *
(soComp.radius *
0.5f);
newPos.y =
charPos.y;
if (trans.node) {
trans.node
->setPosition(
newPos);
}
trans.position =
newPos;
}
state.state =
State::Executing;
state.target
@@ -407,13 +480,19 @@ void SmartObjectSystem::update(float deltaTime)
ZERO;
return;
}
} else {
targetPos =
state.target.path
[state.target
.pathIndex];
toTarget = targetPos - charPos;
// Too far - recalculate path
state.target.path.clear();
state.target.path.push_back(
objPos);
state.target.pathIndex = 0;
cc.linearVelocity =
Ogre::Vector3::ZERO;
return;
}
targetPos =
state.target.path
[state.target.pathIndex];
toTarget = targetPos - charPos;
}
// Only set velocity direction - AnimationTreeSystem
@@ -530,6 +609,9 @@ void SmartObjectSystem::update(float deltaTime)
// --- State: Pathfinding ---
if (state.state == State::Pathfinding) {
if (!state.target.smartObject.is_alive()) {
std::cout
<< "[SO] Pathfinding: target dead, going idle"
<< std::endl;
state.state = State::Idle;
return;
}
@@ -543,6 +625,9 @@ void SmartObjectSystem::update(float deltaTime)
.get<SmartObjectComponent>();
if (isInRange(charPos, objPos, soComp.radius,
soComp.height)) {
std::cout
<< "[SO] Pathfinding: already in range, executing"
<< std::endl;
state.state = State::Executing;
state.target.isExecuting = true;
state.target.executionTimer = 0.0f;
@@ -558,13 +643,25 @@ void SmartObjectSystem::update(float deltaTime)
state.target.path);
if (found &&
!state.target.path.empty()) {
std::cout
<< "[SO] Pathfinding: path found with "
<< state.target.path
.size()
<< " waypoints"
<< std::endl;
state.state = State::Moving;
} else {
std::cout
<< "[SO] Pathfinding: no path found, going idle"
<< std::endl;
state.state = State::Idle;
cc.linearVelocity =
Ogre::Vector3::ZERO;
}
} else {
std::cout
<< "[SO] Pathfinding: no navmesh, going direct"
<< std::endl;
state.target.path.clear();
state.target.path.push_back(objPos);
state.target.pathIndex = 0;
@@ -577,6 +674,9 @@ void SmartObjectSystem::update(float deltaTime)
if (state.state == State::Moving) {
if (!state.target.smartObject.is_alive() ||
state.target.path.empty()) {
std::cout
<< "[SO] Moving: target dead or path empty, idle"
<< std::endl;
state.state = State::Idle;
cc.linearVelocity = Ogre::Vector3::ZERO;
return;
@@ -589,8 +689,13 @@ void SmartObjectSystem::update(float deltaTime)
auto &soComp =
state.target.smartObject
.get<SmartObjectComponent>();
// Always check range first
if (isInRange(charPos, objPos, soComp.radius,
soComp.height)) {
std::cout
<< "[SO] Moving: in range, executing"
<< std::endl;
state.state = State::Executing;
state.target.isExecuting = true;
state.target.executionTimer = 0.0f;
@@ -619,8 +724,53 @@ void SmartObjectSystem::update(float deltaTime)
}
}
// Check if path is exhausted
if (state.target.pathIndex >=
(int)state.target.path.size()) {
float distToObj =
charPos.distance(objPos);
std::cout
<< "[SO] Moving: path exhausted, dist="
<< distToObj << " radius*2="
<< soComp.radius * 2.0f
<< std::endl;
// If close enough, teleport to range
// and execute
if (distToObj < soComp.radius * 2.0f) {
std::cout
<< "[SO] Moving: close enough, teleporting"
<< std::endl;
Ogre::Vector3 dirToObj =
objPos - charPos;
dirToObj.y = 0;
float xzDist =
dirToObj.length();
if (xzDist > 0.01f) {
dirToObj /= xzDist;
Ogre::Vector3 newPos =
objPos -
dirToObj *
(soComp.radius *
0.5f);
newPos.y = charPos.y;
if (trans.node) {
trans.node->setPosition(
newPos);
}
trans.position = newPos;
}
state.state = State::Executing;
state.target.isExecuting = true;
state.target.executionTimer =
0.0f;
cc.linearVelocity =
Ogre::Vector3::ZERO;
return;
}
// Too far - recalculate path
std::cout
<< "[SO] Moving: too far, recalc path"
<< std::endl;
state.target.path.clear();
state.target.path.push_back(objPos);
state.target.pathIndex = 0;
@@ -631,12 +781,54 @@ void SmartObjectSystem::update(float deltaTime)
.path[state.target.pathIndex];
Ogre::Vector3 toTarget = targetPos - charPos;
if (toTarget.length() < 0.5f) {
// Waypoint arrival threshold - generous since
// waypoints are just guide points
const float WAYPOINT_THRESHOLD = 1.0f;
if (toTarget.length() < WAYPOINT_THRESHOLD) {
state.target.pathIndex++;
if (state.target.pathIndex >=
(int)state.target.path.size()) {
toTarget = objPos - charPos;
if (toTarget.length() < 0.5f) {
// Path exhausted - teleport to
// range and execute if close
// enough
float distToObj =
charPos.distance(
objPos);
std::cout
<< "[SO] Moving: last waypoint reached, dist="
<< distToObj
<< " radius*2="
<< soComp.radius * 2.0f
<< std::endl;
if (distToObj <
soComp.radius * 2.0f) {
std::cout
<< "[SO] Moving: close enough at waypoint, teleporting"
<< std::endl;
Ogre::Vector3 dirToObj =
objPos -
charPos;
dirToObj.y = 0;
float xzDist =
dirToObj.length();
if (xzDist > 0.01f) {
dirToObj /=
xzDist;
Ogre::Vector3 newPos =
objPos -
dirToObj *
(soComp.radius *
0.5f);
newPos.y =
charPos.y;
if (trans.node) {
trans.node
->setPosition(
newPos);
}
trans.position =
newPos;
}
state.state =
State::Executing;
state.target
@@ -650,13 +842,22 @@ void SmartObjectSystem::update(float deltaTime)
ZERO;
return;
}
} else {
targetPos =
state.target.path
[state.target
.pathIndex];
toTarget = targetPos - charPos;
// Too far - recalculate path
std::cout
<< "[SO] Moving: too far at waypoint, recalc"
<< std::endl;
state.target.path.clear();
state.target.path.push_back(
objPos);
state.target.pathIndex = 0;
cc.linearVelocity =
Ogre::Vector3::ZERO;
return;
}
targetPos =
state.target.path
[state.target.pathIndex];
toTarget = targetPos - charPos;
}
toTarget.y = 0;
@@ -699,10 +900,24 @@ void SmartObjectSystem::update(float deltaTime)
db->findAction(
state.target.actionName);
if (action) {
// Kick off the action's
// behavior tree via
// BehaviorTreeSystem's
// ActionDebug path
debug.isRunning = true;
debug.currentActionName =
state.target.actionName;
state.target.executionTimer +=
deltaTime;
if (state.target.executionTimer >
3.0f) {
// Stop behavior tree
// evaluation
debug.isRunning = false;
debug.currentActionName
.clear();
bb.apply(
action->effects);
state.state =