Smart objects work!
This commit is contained in:
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user