载入中...
搜索中...
未找到
Crowd.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4
5
6#include <algorithm>
7#include <cmath>
8#include <cstdint>
9#include <string>
10#include <unordered_map>
11#include <vector>
12
13
14namespace eve::crowd {
15namespace {
16
17enum Action : int32_t { kIdle = 0, kFlow = 1, kSeek = 2, kBoids = 3 };
18
19int actionFromName(const std::string &name) {
20 if (name == "idle") return kIdle;
21 if (name == "flow") return kFlow;
22 if (name == "seek") return kSeek;
23 if (name == "boids") return kBoids;
24 return -1;
25}
26
27const char *actionName(int action) {
28 switch (action) {
29 case kIdle: return "idle";
30 case kFlow: return "flow";
31 case kSeek: return "seek";
32 case kBoids: return "boids";
33 default: return "";
34 }
35}
36
37
38} // namespace
39
40
42
43Crowd::Crowd() : impl_(std::make_unique<Impl>()) {}
44Crowd::~Crowd() = default;
45
46// --- 流场 ---
47
48void Crowd::resizeField(int width, int height, float cellSize, float originX, float originY) {
49 impl_->field.resize(width, height, cellSize, originX, originY);
50}
51
52void Crowd::setBlocked(int cx, int cy, bool blocked) {
53 impl_->field.setBlocked(cx, cy, blocked);
54}
55
56void Crowd::setCellCost(int cx, int cy, float cost) {
57 impl_->field.setCellCost(cx, cy, cost);
58}
59
60float Crowd::getCellCost(int cx, int cy) const { return impl_->field.getCellCost(cx, cy); }
61
62void Crowd::buildFlowField(int gx, int gy) {
63 impl_->field.setGoal(gx, gy);
64 impl_->field.build();
65}
66
67void Crowd::addFlowGoal(int gx, int gy) { impl_->field.addGoal(gx, gy); }
68
69void Crowd::clearFlowGoals() { impl_->field.clearGoals(); }
70
71void Crowd::build() { impl_->field.build(); }
72
73bool Crowd::isFieldBuilt() const { return impl_->field.isBuilt(); }
74
75bool Crowd::isReachable(int cx, int cy) const { return impl_->field.isReachable(cx, cy); }
76
77int Crowd::getFieldWidth() const { return impl_->field.getWidth(); }
78int Crowd::getFieldHeight() const { return impl_->field.getHeight(); }
79float Crowd::getCellSize() const { return impl_->field.getCellSize(); }
80float Crowd::getFieldOriginX() const { return impl_->field.getOriginX(); }
81float Crowd::getFieldOriginY() const { return impl_->field.getOriginY(); }
82
83FlowVec Crowd::flowAtWorld(float wx, float wy) const {
84 FlowVec v;
85 impl_->field.flowAtWorld(wx, wy, v.x, v.y);
86 return v;
87}
88
89float Crowd::costAtWorld(float wx, float wy) const { return impl_->field.costAtWorld(wx, wy); }
90
91FlowVec Crowd::flowAtCell(int cx, int cy) const {
92 FlowVec v;
93 impl_->field.flowAtCell(cx, cy, v.x, v.y);
94 return v;
95}
96
97// --- 单位 ---
98
99int Crowd::addAgent(float x, float y, float heading, float radius) {
100 auto &d = *impl_;
101 if (int(d.actions.size()) >= d.maxAgents) return -1;
102 const int id = int(d.xs.size());
103 d.xs.push_back(x);
104 d.ys.push_back(y);
105 d.headings.push_back(heading);
106 d.vxs.push_back(0.f);
107 d.vys.push_back(0.f);
108 d.speeds.push_back(0.f);
109 d.radii.push_back(radius > 0.f ? radius : d.defaultRadius);
110 d.maxSpeeds.push_back(d.defaultSpeed);
111 d.maxAccels.push_back(d.defaultSpeed * 2.f);
112 d.turnRates.push_back(d.defaultTurnRate);
113 d.actions.push_back(kFlow);
114 d.datas.push_back(0);
115 d.avoidancePriorities.push_back(0);
116 d.hasTargets.push_back(0);
117 d.interactions.emplace_back();
118 d.targetXs.push_back(0.f);
119 d.targetYs.push_back(0.f);
120 d.wanderPhases.push_back(float(id) * 2.399963f);
121 d.stableIds.emplace_back();
122 return id;
123}
124
125int Crowd::addNamedAgent(const std::string &stableId, float x, float y, float heading, float radius) {
126 auto &d = *impl_;
127 if (stableId.empty() || d.namedAgents.count(stableId) != 0) return -1;
128 const int index = addAgent(x, y, heading, radius);
129 if (index < 0) return -1;
130 d.stableIds[static_cast<size_t>(index)] = stableId;
131 d.namedAgents[stableId] = index;
132 return index;
133}
134
135bool Crowd::hasNamedAgent(const std::string &stableId) const {
136 return impl_->namedAgents.count(stableId) != 0;
137}
138
139int Crowd::getNamedAgentIndex(const std::string &stableId) const {
140 const auto found = impl_->namedAgents.find(stableId);
141 return found == impl_->namedAgents.end() ? -1 : found->second;
142}
143
144std::string Crowd::getAgentStableId(int index) const {
145 return impl_->validId(index) ? impl_->stableIds[static_cast<size_t>(index)] : std::string{};
146}
147
148bool Crowd::removeNamedAgent(const std::string &stableId) {
149 const int index = getNamedAgentIndex(stableId);
150 return index >= 0 && removeAgent(index);
151}
152
153bool Crowd::removeAgent(int id) {
154 auto &d = *impl_;
155 if (!d.validId(id)) return false;
156 const int last = int(d.xs.size()) - 1;
157 const std::string removedStableId = d.stableIds[static_cast<size_t>(id)];
158 if (id != last) {
159 d.xs[size_t(id)] = d.xs[size_t(last)];
160 d.ys[size_t(id)] = d.ys[size_t(last)];
161 d.headings[size_t(id)] = d.headings[size_t(last)];
162 d.vxs[size_t(id)] = d.vxs[size_t(last)];
163 d.vys[size_t(id)] = d.vys[size_t(last)];
164 d.speeds[size_t(id)] = d.speeds[size_t(last)];
165 d.radii[size_t(id)] = d.radii[size_t(last)];
166 d.maxSpeeds[size_t(id)] = d.maxSpeeds[size_t(last)];
167 d.maxAccels[size_t(id)] = d.maxAccels[size_t(last)];
168 d.turnRates[size_t(id)] = d.turnRates[size_t(last)];
169 d.actions[size_t(id)] = d.actions[size_t(last)];
170 d.datas[size_t(id)] = d.datas[size_t(last)];
171 d.avoidancePriorities[size_t(id)] = d.avoidancePriorities[size_t(last)];
172 d.hasTargets[size_t(id)] = d.hasTargets[size_t(last)];
173 d.interactions[size_t(id)] = d.interactions[size_t(last)];
174 d.targetXs[size_t(id)] = d.targetXs[size_t(last)];
175 d.targetYs[size_t(id)] = d.targetYs[size_t(last)];
176 d.wanderPhases[size_t(id)] = d.wanderPhases[size_t(last)];
177 d.stableIds[size_t(id)] = d.stableIds[size_t(last)];
178 if (!d.stableIds[size_t(id)].empty()) d.namedAgents[d.stableIds[size_t(id)]] = id;
179 }
180 if (!removedStableId.empty()) d.namedAgents.erase(removedStableId);
181 d.xs.pop_back();
182 d.ys.pop_back();
183 d.headings.pop_back();
184 d.vxs.pop_back();
185 d.vys.pop_back();
186 d.speeds.pop_back();
187 d.radii.pop_back();
188 d.maxSpeeds.pop_back();
189 d.maxAccels.pop_back();
190 d.turnRates.pop_back();
191 d.actions.pop_back();
192 d.datas.pop_back();
193 d.avoidancePriorities.pop_back();
194 d.hasTargets.pop_back();
195 d.interactions.pop_back();
196 d.targetXs.pop_back();
197 d.targetYs.pop_back();
198 d.wanderPhases.pop_back();
199 d.stableIds.pop_back();
200 return true;
201}
202
204 auto &d = *impl_;
205 d.xs.clear();
206 d.ys.clear();
207 d.headings.clear();
208 d.vxs.clear();
209 d.vys.clear();
210 d.speeds.clear();
211 d.radii.clear();
212 d.maxSpeeds.clear();
213 d.maxAccels.clear();
214 d.turnRates.clear();
215 d.actions.clear();
216 d.datas.clear();
217 d.avoidancePriorities.clear();
218 d.hasTargets.clear();
219 d.interactions.clear();
220 d.targetXs.clear();
221 d.targetYs.clear();
222 d.wanderPhases.clear();
223 d.stableIds.clear();
224 d.namedAgents.clear();
225 d.gridW = d.gridH = 0;
226}
227
228int Crowd::getAgentCount() const { return int(impl_->xs.size()); }
229
230void Crowd::setMaxAgents(int maxAgents) {
231 impl_->maxAgents = std::max(maxAgents, 0);
232}
233
234int Crowd::getMaxAgents() const { return impl_->maxAgents; }
235
236bool Crowd::setAgentAction(int id, const std::string &action) {
237 if (!impl_->validId(id)) return false;
238 const int a = actionFromName(action);
239 if (a < 0) return false;
240 impl_->actions[size_t(id)] = a;
241 return true;
242}
243
244std::string Crowd::getAgentAction(int id) const {
245 if (!impl_->validId(id)) return "";
246 return actionName(impl_->actions[size_t(id)]);
247}
248
249bool Crowd::setAgentTarget(int id, float tx, float ty) {
250 if (!impl_->validId(id)) return false;
251 impl_->hasTargets[size_t(id)] = 1;
252 impl_->targetXs[size_t(id)] = tx;
253 impl_->targetYs[size_t(id)] = ty;
254 return true;
255}
256
258 if (!impl_->validId(id)) return false;
259 impl_->hasTargets[size_t(id)] = 0;
260 return true;
261}
262
263bool Crowd::setAgentSpeed(int id, float speed) {
264 if (!impl_->validId(id) || speed < 0.f) return false;
265 impl_->maxSpeeds[size_t(id)] = speed;
266 return true;
267}
268
269bool Crowd::setAgentAccel(int id, float accel) {
270 if (!impl_->validId(id) || accel < 0.f) return false;
271 impl_->maxAccels[size_t(id)] = accel;
272 return true;
273}
274
275bool Crowd::setAgentTurnRate(int id, float radPerSec) {
276 if (!impl_->validId(id) || radPerSec < 0.f) return false;
277 impl_->turnRates[size_t(id)] = radPerSec;
278 return true;
279}
280
281bool Crowd::setAgentRadius(int id, float radius) {
282 if (!impl_->validId(id) || radius < 0.f) return false;
283 impl_->radii[size_t(id)] = radius;
284 return true;
285}
286
287bool Crowd::setAgentData(int id, int data) {
288 if (!impl_->validId(id)) return false;
289 impl_->datas[size_t(id)] = data;
290 return true;
291}
292
293int Crowd::getAgentData(int id) const {
294 if (!impl_->validId(id)) return 0;
295 return impl_->datas[size_t(id)];
296}
297
299 if (!impl_->validId(id))
301 Diagnostic::error(DiagnosticCode::NotFound, "Crowd avoidance-priority agent slot was not found", "id"));
302 impl_->avoidancePriorities[size_t(id)] = priority;
304}
305
307 return impl_->validId(id) ? impl_->avoidancePriorities[size_t(id)] : 0;
308}
309
310bool Crowd::setAgentPosition(int id, float x, float y) {
311 if (!impl_->validId(id)) return false;
312 impl_->xs[size_t(id)] = x;
313 impl_->ys[size_t(id)] = y;
314 return true;
315}
316
319 if (!impl_->validId(id)) {
320 s.action = -1;
321 return s;
322 }
323 s.x = impl_->xs[size_t(id)];
324 s.y = impl_->ys[size_t(id)];
325 s.heading = impl_->headings[size_t(id)];
326 s.speed = impl_->speeds[size_t(id)];
327 s.vx = impl_->vxs[size_t(id)];
328 s.vy = impl_->vys[size_t(id)];
329 s.action = impl_->actions[size_t(id)];
330 s.data = impl_->datas[size_t(id)];
331 s.avoidancePriority = impl_->avoidancePriorities[size_t(id)];
332 return s;
333}
334
335// --- 群体参数 ---
336
337void Crowd::setDefaultSpeed(float speed) { impl_->defaultSpeed = std::max(speed, 0.f); }
338void Crowd::setDefaultRadius(float radius) { impl_->defaultRadius = std::max(radius, 0.f); }
339void Crowd::setDefaultTurnRate(float radPerSec) {
340 impl_->defaultTurnRate = std::max(radPerSec, 0.f);
341}
342void Crowd::setArriveRadius(float radius) { impl_->arriveRadius = std::max(radius, 0.f); }
343void Crowd::setSeparationRadius(float radius) { impl_->sepRadius = std::max(radius, 0.f); }
344void Crowd::setPerceptionRadius(float radius) { impl_->perceiveRadius = std::max(radius, 0.f); }
345void Crowd::setSeparationWeight(float weight) { impl_->sepWeight = weight; }
346void Crowd::setAlignmentWeight(float weight) { impl_->alignWeight = weight; }
347void Crowd::setCohesionWeight(float weight) { impl_->cohesionWeight = weight; }
348void Crowd::setWanderWeight(float weight) { impl_->wanderWeight = weight; }
349void Crowd::setGoalWeight(float weight) { impl_->goalWeight = weight; }
350void Crowd::setResolveOverlaps(bool enable) { impl_->resolveOverlaps = enable; }
351void Crowd::setClampToField(bool enable) { impl_->clampToField = enable; }
352
353
354} // namespace eve::crowd
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
const std::string & s
int priority
float cx
Definition CardTypes.cpp:33
float cy
Definition CardTypes.cpp:34
eve::resource::CostSpec cost
float v
std::uint32_t height
std::uint32_t width
std::string name
MeleePoint3 a
Definition MeleeHit.cpp:40
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
float radius
std::string action
Definition PlayHost.cpp:117
std::string id
Definition PlayHost.cpp:108
float d
bool found
V3 heading
Definition TreeMesh.cpp:292
uint32_t index
float wx
float wy
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
群体行为模块:连续流场寻路 + 海量单位移动/转向/行动 + Boids 鸟群。
Definition Crowd.h:116
FlowVec flowAtCell(int cx, int cy) const
格级流场方向。
Definition Crowd.cpp:91
void setCohesionWeight(float weight)
Boids 聚合力权重。
Definition Crowd.cpp:347
bool removeAgent(int id)
删除单位(swap-pop O(1))。
Definition Crowd.cpp:153
AgentState getAgentState(int id) const
读取单位状态快照(非法 id 返回 action=-1)。
Definition Crowd.cpp:317
void setClampToField(bool enable)
是否把单位钳制在流场边界内(默认开)。
Definition Crowd.cpp:351
std::string getAgentAction(int id) const
查询行动名。
Definition Crowd.cpp:244
void setWanderWeight(float weight)
Boids wander 权重。
Definition Crowd.cpp:348
void build()
执行 Dijkstra 建场。
Definition Crowd.cpp:71
void addFlowGoal(int gx, int gy)
追加目标格(多目标)。
Definition Crowd.cpp:67
bool setAgentPosition(int id, float x, float y)
直接放置单位。
Definition Crowd.cpp:310
void resizeField(int width, int height, float cellSize, float originX, float originY)
配置流场网格(世界单位/格)。
Definition Crowd.cpp:48
float costAtWorld(float wx, float wy) const
世界坐标积分代价(场外返回 kUnreachable)。
Definition Crowd.cpp:89
bool isFieldBuilt() const
是否已建场。
Definition Crowd.cpp:73
int getNamedAgentIndex(const std::string &stableId) const
Resolve a stable logical identifier to the current compact slot.
Definition Crowd.cpp:139
int getMaxAgents() const
Returns the max agents.
Definition Crowd.cpp:234
bool setAgentData(int id, int data)
设置游戏自定义标记。
Definition Crowd.cpp:287
int getAgentCount() const
当前单位数。
Definition Crowd.cpp:228
bool setAgentAccel(int id, float accel)
设置加速度上限(默认 maxSpeed×2)。
Definition Crowd.cpp:269
void setDefaultRadius(float radius)
新单位默认半径。
Definition Crowd.cpp:338
void setSeparationRadius(float radius)
分离/邻居查询半径。
Definition Crowd.cpp:343
void setDefaultSpeed(float speed)
新单位默认速度。
Definition Crowd.cpp:337
void clearFlowGoals()
清空目标列表。
Definition Crowd.cpp:69
void buildFlowField(int gx, int gy)
单目标快捷建场(clearGoals + addGoal + build)。
Definition Crowd.cpp:62
int addNamedAgent(const std::string &stableId, float x, float y, float heading, float radius)
Add an agent with an editor/game-stable logical identifier.
Definition Crowd.cpp:125
int addAgent(float x, float y, float heading, float radius)
添加单位;返回 id(=槽位索引;删除后 id 不稳定)。
Definition Crowd.cpp:99
void setBlocked(int cx, int cy, bool blocked)
设置/清除某格阻挡。
Definition Crowd.cpp:52
int getAgentAvoidancePriority(int id) const
Return overlap-resolution priority, or zero for an invalid id.
Definition Crowd.cpp:306
int getFieldWidth() const
网格信息访问器(调试渲染用)。
Definition Crowd.cpp:77
bool isReachable(int cx, int cy) const
某格是否可达。
Definition Crowd.cpp:75
float getCellSize() const
Returns the cell size.
Definition Crowd.cpp:79
float getFieldOriginY() const
Returns the field origin y.
Definition Crowd.cpp:81
void setResolveOverlaps(bool enable)
是否做位置重叠消解 pass(默认开)。
Definition Crowd.cpp:350
Crowd()
Crowd.
Definition Crowd.cpp:43
void setMaxAgents(int maxAgents)
单位容量上限(默认 100000)。
Definition Crowd.cpp:230
bool removeNamedAgent(const std::string &stableId)
Remove an agent by stable logical identifier.
Definition Crowd.cpp:148
~Crowd() override
Crowd.
std::string getAgentStableId(int index) const
Return the stable logical identifier for a compact slot.
Definition Crowd.cpp:144
bool clearAgentTarget(int id)
清除目标点。
Definition Crowd.cpp:257
void clearAgents()
清空全部单位。
Definition Crowd.cpp:203
bool setAgentSpeed(int id, float speed)
设置最大速度(世界单位/秒)。
Definition Crowd.cpp:263
FlowVec flowAtWorld(float wx, float wy) const
世界坐标流场方向(双线性插值;场外返回零向量)。
Definition Crowd.cpp:83
float getFieldOriginX() const
Returns the field origin x.
Definition Crowd.cpp:80
bool setAgentAction(int id, const std::string &action)
设置行动:"idle" | "flow" | "seek" | "boids"。
Definition Crowd.cpp:236
float getCellCost(int cx, int cy) const
查询地形代价。
Definition Crowd.cpp:60
int getFieldHeight() const
Returns the field height.
Definition Crowd.cpp:78
void setGoalWeight(float weight)
Boids 目标偏置权重。
Definition Crowd.cpp:349
void setDefaultTurnRate(float radPerSec)
新单位默认转向速率(弧度/秒)。
Definition Crowd.cpp:339
bool setAgentRadius(int id, float radius)
设置半径。
Definition Crowd.cpp:281
bool hasNamedAgent(const std::string &stableId) const
Return whether a stable logical agent exists.
Definition Crowd.cpp:135
Result< void > setAgentAvoidancePriority(int id, int priority)
Set overlap-resolution priority; higher values yield less.
Definition Crowd.cpp:298
void setSeparationWeight(float weight)
Boids 分离力权重。
Definition Crowd.cpp:345
void setCellCost(int cx, int cy, float cost)
设置地形代价(0=阻挡,>=1 可走)。
Definition Crowd.cpp:56
void setArriveRadius(float radius)
seek 到达减速半径。
Definition Crowd.cpp:342
bool setAgentTurnRate(int id, float radPerSec)
设置转向速率上限(弧度/秒)。
Definition Crowd.cpp:275
int getAgentData(int id) const
Returns the agent data.
Definition Crowd.cpp:293
void setPerceptionRadius(float radius)
对齐/聚合感知半径(Boids;默认 64,可大于分离半径)。
Definition Crowd.cpp:344
void setAlignmentWeight(float weight)
Boids 对齐力权重。
Definition Crowd.cpp:346
bool setAgentTarget(int id, float tx, float ty)
设置世界目标点(seek 直接寻点,boids 作迁移偏置)。
Definition Crowd.cpp:249
单个单位的状态快照(脚本 getAgentState 返回值)。 action: 0=idle, 1=flow, 2=seek, 3=boids。
Definition Crowd.h:19
int action
行动枚举(-1=非法 id)
Definition Crowd.h:26
Private crowd runtime storage. @cost Linear in agent count for SOA vectors and transient broadphase/a...
流场采样结果(脚本 flowAtWorld / flowAtCell 返回值)。
Definition Crowd.h:32