Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
Task_MoveToLocation.cpp
Go to the documentation of this file.
1/**
2 * @file Task_MoveToLocation.cpp
3 * @brief Atomic task: move entity toward a target location.
4 * @author Olympe Engine
5 * @date 2026-02-23
6 *
7 * @details
8 * Dual-mode movement task.
9 *
10 * World mode (ctx.ComponentFacade with Position and Movement set):
11 * Reads the entity's PositionComponent and writes to its MovementComponent.
12 * Sets Velocity = dir * speed while the entity is farther than
13 * ARRIVAL_TOLERANCE from the target; zeroes Velocity and returns Success
14 * once it arrives. A physics/movement ECS system is responsible for
15 * integrating the velocity.
16 *
17 * Headless mode (ctx.ComponentFacade is nullptr or components are absent):
18 * Reads and writes the "Position" key in ctx.LocalBB, integrating position
19 * analytically using ctx.DeltaTime.
20 *
21 * C++14 compliant - no C++17/20 features.
22 */
23
24#include "Task_MoveToLocation.h"
25#include "../../AtomicTaskRegistry.h"
26#include "../../LocalBlackboard.h"
27#include "../../TaskWorldFacade.h"
28#include "../../../system/system_utils.h"
29
30#include <cmath>
31
32namespace Olympe {
33
34// ---------------------------------------------------------------------------
35// Constants
36// ---------------------------------------------------------------------------
37
38static const float DEFAULT_SPEED = 100.0f;
39static const float ARRIVAL_TOLERANCE = 0.5f;
40static const char* BB_KEY_POSITION = "Position";
41
42// ---------------------------------------------------------------------------
43// Constructor / Abort
44// ---------------------------------------------------------------------------
45
47
49{
50 SYSTEM_LOG << "[Task_MoveToLocation] Abort()\n";
51}
52
53// ---------------------------------------------------------------------------
54// Execute (legacy fallback - not used when ExecuteWithContext is available)
55// ---------------------------------------------------------------------------
56
58{
59 return TaskStatus::Failure; // requires context; use ExecuteWithContext
60}
61
62// ---------------------------------------------------------------------------
63// ExecuteWithContext
64// ---------------------------------------------------------------------------
65
67 const ParameterMap& params)
68{
69 // --- Resolve Target parameter ---
70 ::Vector target(0.0f, 0.0f, 0.0f);
71 {
72 auto it = params.find("Target");
73 if (it != params.end() && it->second.GetType() == VariableType::Vector)
74 {
75 target = it->second.AsVector();
76 }
77 else
78 {
79 SYSTEM_LOG << "[Task_MoveToLocation] Missing or invalid 'Target' parameter\n";
81 }
82 }
83
84 // --- Resolve Speed parameter (optional) ---
85 float speed = DEFAULT_SPEED;
86 {
87 auto it = params.find("Speed");
88 if (it != params.end() && it->second.GetType() == VariableType::Float)
89 {
90 speed = it->second.AsFloat();
91 if (speed <= 0.0f) speed = DEFAULT_SPEED;
92 }
93 }
94
95 // -----------------------------------------------------------------------
96 // World mode: use ECS PositionComponent + MovementComponent when available
97 // -----------------------------------------------------------------------
98 if (ctx.ComponentFacade
99 && ctx.ComponentFacade->Position
100 && ctx.ComponentFacade->Movement)
101 {
102 ::Vector& pos = ctx.ComponentFacade->Position->Position;
103 ::Vector& velocity = ctx.ComponentFacade->Movement->Velocity;
104
105 ::Vector delta = target - pos;
106 float dist = delta.Norm();
107
108 SYSTEM_LOG << "[Task_MoveToLocation] (WorldMode) Entity " << ctx.Entity
109 << " pos=(" << pos.x << "," << pos.y << ")"
110 << " target=(" << target.x << "," << target.y << ")"
111 << " dist=" << dist << "\n";
112
113 if (dist <= ARRIVAL_TOLERANCE)
114 {
115 velocity = ::Vector(0.0f, 0.0f, 0.0f);
116 SYSTEM_LOG << "[Task_MoveToLocation] (WorldMode) Entity " << ctx.Entity
117 << " reached target - Success\n";
118 return TaskStatus::Success;
119 }
120
121 ::Vector dir = delta * (1.0f / dist);
122 velocity = dir * speed;
123 return TaskStatus::Running;
124 }
125
126 // -----------------------------------------------------------------------
127 // Headless mode: read / write "Position" via LocalBlackboard
128 // -----------------------------------------------------------------------
129
130 // --- Read current position from LocalBlackboard ---
131 if (!ctx.LocalBB || !ctx.LocalBB->HasVariable(BB_KEY_POSITION))
132 {
133 SYSTEM_LOG << "[Task_MoveToLocation] 'Position' key not found in LocalBlackboard\n";
134 return TaskStatus::Failure;
135 }
136
138 try
139 {
140 pos = ctx.LocalBB->GetValue(BB_KEY_POSITION).AsVector();
141 }
142 catch (...)
143 {
144 SYSTEM_LOG << "[Task_MoveToLocation] Failed to read 'Position' from LocalBlackboard\n";
145 return TaskStatus::Failure;
146 }
147
148 // --- Compute direction and step ---
149 ::Vector delta = target - pos;
150 float dist = delta.Norm();
151
152 SYSTEM_LOG << "[Task_MoveToLocation] Entity " << ctx.Entity
153 << " pos=(" << pos.x << "," << pos.y << ")"
154 << " target=(" << target.x << "," << target.y << ")"
155 << " dist=" << dist << "\n";
156
157 float step = speed * ctx.DeltaTime;
158
159 if (dist <= ARRIVAL_TOLERANCE || dist <= step)
160 {
161 // Snap to target and report success.
162 try
163 {
164 ctx.LocalBB->SetValue(BB_KEY_POSITION, TaskValue(target));
165 }
166 catch (...) {}
167
168 SYSTEM_LOG << "[Task_MoveToLocation] Entity " << ctx.Entity
169 << " reached target - Success\n";
170 return TaskStatus::Success;
171 }
172
173 // Move step units toward target.
174 ::Vector dir = delta * (step / dist);
176
177 try
178 {
179 ctx.LocalBB->SetValue(BB_KEY_POSITION, TaskValue(newPos));
180 }
181 catch (...)
182 {
183 SYSTEM_LOG << "[Task_MoveToLocation] Failed to write 'Position' to LocalBlackboard\n";
184 return TaskStatus::Failure;
185 }
186
187 return TaskStatus::Running;
188}
189
190REGISTER_ATOMIC_TASK(Task_MoveToLocation, "Task_MoveToLocation")
191
192} // namespace Olympe
#define REGISTER_ATOMIC_TASK(ClassName, Id)
Registers a factory for ClassName under Id at static init time.
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
Atomic task that moves an entity toward a target location.
std::unordered_map< std::string, TaskValue > ParameterMap
Convenience alias for the parameter map passed to Execute().
Definition IAtomicTask.h:67
C++14-compliant type-safe value container for task parameters.
Moves an entity toward a target location each tick.
void Abort() override
Aborts the task, releasing any in-progress state.
TaskStatus ExecuteWithContext(const AtomicTaskContext &ctx, const ParameterMap &params) override
Executes the atomic task for one frame with full runtime context.
TaskStatus Execute(const ParameterMap &params) override
Executes the atomic task for one frame.
float Norm() const
Definition vector.h:71
float y
Definition vector.h:25
float x
Definition vector.h:25
< Provides AssetID and INVALID_ASSET_ID
@ Float
Single-precision float.
@ Vector
3-component vector (Vector from vector.h)
TaskStatus
Result code returned by IAtomicTask::Execute().
Definition IAtomicTask.h:38
@ Success
Task completed successfully.
@ Running
Task is still in progress (multi-frame tasks)
@ Failure
Task failed.
static const float DEFAULT_SPEED
static const float ARRIVAL_TOLERANCE
static const char * BB_KEY_POSITION
Lightweight context bundle passed to IAtomicTask::ExecuteWithContext().
#define SYSTEM_LOG