4#include <simplesquirrel/simplesquirrel.hpp>
8Result<SpawnBatch> readSpawnBatch(ssq::Array agents, ssq::Table
options) {
10 if (agents.size() > 1024)
14 const auto mode =
options.get<std::string>(
"policy");
17 else if (mode ==
"nearestFree")
19 else if (mode ==
"pushNeighbors")
24 batch.maxDistance =
options.get<
float>(
"maxDistance");
25 batch.searchSpacing =
options.get<
float>(
"searchSpacing");
26 batch.maxPasses =
options.get<
int>(
"maxPasses");
27 batch.maxChecks =
options.get<
int>(
"maxChecks");
28 for (
size_t i = 0; i < agents.size(); ++i) {
29 auto item = agents.get<ssq::Table>(i);
31 request.stableId = item.get<std::string>(
"stableId");
32 request.x = item.get<
float>(
"x");
33 request.y = item.get<
float>(
"y");
34 request.heading = item.get<
float>(
"heading");
35 request.radius = item.get<
float>(
"radius");
36 request.interaction = {item.get<
float>(
"pushability"), item.get<
bool>(
"holdPosition"),
37 item.get<
int>(
"layer"), item.get<
int>(
"mask")};
38 batch.agents.push_back(std::move(
request));
41 }
catch (
const std::exception &
error) {
50void Crowd::expose(ssq::Table &table) {
54 auto state =
table.addClass<AgentState>(
"CrowdAgentState", ssq::Class::Ctor<AgentState()>());
65 auto flow =
table.addClass<FlowVec>(
"CrowdFlowVec", ssq::Class::Ctor<FlowVec()>());
70void Crowd::expose(ssq::Class &
cls) {
115 cls.addFunc(
"setAgentAvoidancePriority",
118 cls.addFunc(
"setAgentInteraction", [
vm =
cls.getHandle()](
Crowd *crowd,
int id,
float pushability,
119 bool holdPosition,
int layer,
int mask) {
120 return script::projectResult(vm, crowd->setAgentInteraction(id, {pushability, holdPosition, layer, mask}));
122 cls.addFunc(
"getAgentInteraction", [
vm =
cls.getHandle()](Crowd *crowd,
int id) {
124 return Value(Value::Object{{
"pushability", Value(policy.pushability)},
125 {
"holdPosition", Value(policy.holdPosition)},
126 {
"layer", Value(policy.layer)},
127 {
"mask", Value(policy.mask)}});
130 cls.addFunc(
"setAgentPosition", &Crowd::setAgentPosition);
131 cls.addFunc(
"applySpawnBatch", [
vm =
cls.getHandle()](Crowd *crowd, ssq::Array agents, ssq::Table
options) {
132 auto batch = readSpawnBatch(std::move(agents), std::move(
options));
133 const auto project = [](
const SpawnReceipt &receipt) {
135 for (
const auto &item : receipt.
created)
139 {
"displacedAgents",
Value(receipt.displacedAgents)},
140 {
"checks",
Value(receipt.checks)}});
145 cls.addFunc(
"getAgentState", &Crowd::getAgentState);
148 cls.addFunc(
"setDefaultSpeed", &Crowd::setDefaultSpeed);
149 cls.addFunc(
"setDefaultRadius", &Crowd::setDefaultRadius);
150 cls.addFunc(
"setDefaultTurnRate", &Crowd::setDefaultTurnRate);
151 cls.addFunc(
"setArriveRadius", &Crowd::setArriveRadius);
152 cls.addFunc(
"setSeparationRadius", &Crowd::setSeparationRadius);
153 cls.addFunc(
"setPerceptionRadius", &Crowd::setPerceptionRadius);
154 cls.addFunc(
"setSeparationWeight", &Crowd::setSeparationWeight);
155 cls.addFunc(
"setAlignmentWeight", &Crowd::setAlignmentWeight);
156 cls.addFunc(
"setCohesionWeight", &Crowd::setCohesionWeight);
157 cls.addFunc(
"setWanderWeight", &Crowd::setWanderWeight);
158 cls.addFunc(
"setGoalWeight", &Crowd::setGoalWeight);
159 cls.addFunc(
"setResolveOverlaps", &Crowd::setResolveOverlaps);
160 cls.addFunc(
"setClampToField", &Crowd::setClampToField);
161 cls.addFunc(
"configureAvoidance", [
vm =
cls.getHandle()](Crowd *crowd,
bool enabled,
float horizon,
float margin,
165 cls.addFunc(
"getAvoidanceSettings", [
vm =
cls.getHandle()](Crowd *crowd) {
166 const auto settings = crowd->getAvoidanceSettings();
167 ssq::Table result(
vm);
168 result.set(
"enabled",
settings.enabled);
169 result.set(
"horizon",
settings.horizon);
170 result.set(
"margin",
settings.margin);
171 result.set(
"maxNeighbors",
settings.maxNeighbors);
176 cls.addFunc(
"getPositions", [](Crowd *
c, ssq::Array xs, ssq::Array ys) {
178 const size_t n = std::min<size_t>({xs.size(), ys.size(),
c->impl_->xs.size()});
179 for (
size_t i = 0; i <
n; ++i) {
180 xs.set(i,
c->impl_->xs[i]);
181 ys.set(i,
c->impl_->ys[i]);
184 cls.addFunc(
"getHeadings", [](Crowd *
c, ssq::Array hs) {
186 const size_t n = std::min<size_t>(hs.size(),
c->impl_->headings.size());
187 for (
size_t i = 0; i <
n; ++i) hs.set(i,
c->impl_->headings[i]);
189 cls.addFunc(
"step", &Crowd::step);
190 cls.addFunc(
"advance", [
vm =
cls.getHandle()](Crowd *crowd,
float dt) {
192 return Value(Value::Object{{
"avoidanceChecks", Value(report.avoidanceChecks)},
193 {
"avoidanceTruncations", Value(report.avoidanceTruncations)},
194 {
"substeps", Value(report.substeps)},
195 {
"unresolvedContacts", Value(report.unresolvedContacts)},
196 {
"unresolvedWalls", Value(report.unresolvedWalls)},
197 {
"maxPenetration", Value(report.maxPenetration)}});
const GltfImportRequest & request
const SquirrelValueOptions & options
The single Squirrel projection for common Result, Status and Value.
TerrainThermalSettings settings
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.
virtual std::string getName() const =0
Returns the name.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
std::map< std::string, Value > Object
std::vector< Value > Array
FlowVec flowAtCell(int cx, int cy) const
格级流场方向。
bool removeAgent(int id)
删除单位(swap-pop O(1))。
std::string getAgentAction(int id) const
查询行动名。
void build()
执行 Dijkstra 建场。
void addFlowGoal(int gx, int gy)
追加目标格(多目标)。
void resizeField(int width, int height, float cellSize, float originX, float originY)
配置流场网格(世界单位/格)。
float costAtWorld(float wx, float wy) const
世界坐标积分代价(场外返回 kUnreachable)。
bool isFieldBuilt() const
是否已建场。
int getNamedAgentIndex(const std::string &stableId) const
Resolve a stable logical identifier to the current compact slot.
int getMaxAgents() const
Returns the max agents.
bool setAgentData(int id, int data)
设置游戏自定义标记。
int getAgentCount() const
当前单位数。
bool setAgentAccel(int id, float accel)
设置加速度上限(默认 maxSpeed×2)。
void clearFlowGoals()
清空目标列表。
void buildFlowField(int gx, int gy)
单目标快捷建场(clearGoals + addGoal + build)。
int addNamedAgent(const std::string &stableId, float x, float y, float heading, float radius)
Add an agent with an editor/game-stable logical identifier.
int addAgent(float x, float y, float heading, float radius)
添加单位;返回 id(=槽位索引;删除后 id 不稳定)。
void setBlocked(int cx, int cy, bool blocked)
设置/清除某格阻挡。
int getAgentAvoidancePriority(int id) const
Return overlap-resolution priority, or zero for an invalid id.
int getFieldWidth() const
网格信息访问器(调试渲染用)。
bool isReachable(int cx, int cy) const
某格是否可达。
float getCellSize() const
Returns the cell size.
float getFieldOriginY() const
Returns the field origin y.
void setMaxAgents(int maxAgents)
单位容量上限(默认 100000)。
bool removeNamedAgent(const std::string &stableId)
Remove an agent by stable logical identifier.
std::string getAgentStableId(int index) const
Return the stable logical identifier for a compact slot.
bool clearAgentTarget(int id)
清除目标点。
void clearAgents()
清空全部单位。
bool setAgentSpeed(int id, float speed)
设置最大速度(世界单位/秒)。
FlowVec flowAtWorld(float wx, float wy) const
世界坐标流场方向(双线性插值;场外返回零向量)。
float getFieldOriginX() const
Returns the field origin x.
bool setAgentAction(int id, const std::string &action)
设置行动:"idle" | "flow" | "seek" | "boids"。
float getCellCost(int cx, int cy) const
查询地形代价。
int getFieldHeight() const
Returns the field height.
bool setAgentRadius(int id, float radius)
设置半径。
bool hasNamedAgent(const std::string &stableId) const
Return whether a stable logical agent exists.
void setCellCost(int cx, int cy, float cost)
设置地形代价(0=阻挡,>=1 可走)。
bool setAgentTurnRate(int id, float radPerSec)
设置转向速率上限(弧度/秒)。
int getAgentData(int id) const
Returns the agent data.
bool setAgentTarget(int id, float tx, float ty)
设置世界目标点(seek 直接寻点,boids 作迁移偏置)。
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
ssq::Table project(HSQUIRRELVM vm, const eve::Result< void > &result)
Project a completed editing result that has no payload.
std::unordered_map< std::string, SkillDefinition > & table()
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
int avoidancePriority
Higher-priority agents yield less during overlap resolution.