载入中...
搜索中...
未找到
MotionScriptBindings.cpp
浏览该文件的文档.
2
8#include "common/Exception.h"
9
10#include <simplesquirrel/simplesquirrel.hpp>
11
12#include <cstdint>
13#include <string>
14#include <utility>
15
16namespace eve::animation {
17namespace {
18
19[[noreturn]] void throwMotionError(const eve::Diagnostic *diag) {
20 throw Exception("%s", diag ? diag->message().c_str() : "Motion error");
21}
22
23MotionLoopMode parseLoopMode(const std::string &mode) {
24 if (mode.empty() || mode == "restart") return MotionLoopMode::Restart;
25 if (mode == "yoyo") return MotionLoopMode::Yoyo;
26 throw Exception("Motion.loops: unknown mode '%s' (use restart|yoyo)", mode.c_str());
27}
28
29Animation *requireAnimation(Animation *animation) {
30 if (!animation) throw Exception("MotionSequence: Animation is null");
31 return animation;
32}
33
34class ScriptMotionHandle {
35public:
36 ScriptMotionHandle(MotionRuntime *runtime, MotionHandle handle)
37 : runtime_(runtime), handle_(handle) {}
38
39 bool isActive() const { return runtime_ && runtime_->isActive(handle_); }
40
41 float value() const {
42 if (!runtime_) throw Exception("Motion.value: no runtime");
43 auto result = runtime_->floatValue(handle_);
44 if (!result.ok()) throwMotionError(result.error());
45 return result.value();
46 }
47
48 void complete() {
49 if (!runtime_) throw Exception("Motion.complete: no runtime");
50 auto result = runtime_->complete(handle_);
51 if (!result.ok()) throwMotionError(result.error());
52 }
53
54 void cancel() {
55 if (!runtime_) throw Exception("Motion.cancel: no runtime");
56 auto result = runtime_->cancel(handle_);
57 if (!result.ok()) throwMotionError(result.error());
58 }
59
60private:
61 MotionRuntime *runtime_ = nullptr;
62 MotionHandle handle_{};
63};
64
65class ScriptMotionBuilder {
66public:
67 ScriptMotionBuilder(Animation *animation, float from, float to, float duration)
68 : animation_(animation) {
69 if (!animation_) throw Exception("MotionBuilder: Animation is null");
70 desc_.from = from;
71 desc_.to = to;
72 desc_.duration = duration;
73 }
74
75 void ease(std::string kind) { desc_.ease = std::move(kind); }
76 void delay(float seconds) { desc_.delay = seconds; }
77 void loops(int count, std::string mode = "restart") {
78 desc_.loops = count;
79 desc_.loopMode = parseLoopMode(mode);
80 }
81 void cancelOnError(bool enabled) { desc_.cancelOnError = enabled; }
82 void frequency(int count) { desc_.frequency = count; }
83 void dampingRatio(float ratio) { desc_.dampingRatio = ratio; }
84 void seed(int value) { desc_.seed = static_cast<std::uint32_t>(value); }
85 void stylePunch() { desc_.style = MotionStyle::Punch; }
86 void styleShake() { desc_.style = MotionStyle::Shake; }
87
88 ScriptMotionHandle *run() {
89 ensureLive();
90 consumed_ = true;
91 desc_.sink = nullptr;
92 auto spawned = animation_->motions().spawnFloat(desc_);
93 if (!spawned.ok()) throwMotionError(spawned.error());
94 return new ScriptMotionHandle(&animation_->motions(), spawned.value());
95 }
96
97 [[nodiscard]] MotionRuntime &runtime() {
98 ensureLive();
99 return animation_->motions();
100 }
101
102 [[nodiscard]] eve::Result<MotionRuntime::FloatDesc> takeDesc() {
103 ensureLive();
104 consumed_ = true;
105 return eve::Result<MotionRuntime::FloatDesc>::success(std::move(desc_));
106 }
107
108private:
109 void ensureLive() {
110 if (!animation_) throw Exception("MotionBuilder: Animation is null");
111 if (consumed_) throw Exception("MotionBuilder: already consumed (run/append)");
112 }
113
114 Animation *animation_ = nullptr;
115 MotionRuntime::FloatDesc desc_{};
116 bool consumed_ = false;
117};
118
119class ScriptMotionSequenceHandle {
120public:
121 explicit ScriptMotionSequenceHandle(MotionSequenceHandle handle) : handle_(std::move(handle)) {}
122
123 bool isActive() const { return handle_.isActive(); }
124 int childCount() const { return handle_.childCount(); }
125
126 void complete() {
127 auto result = handle_.complete();
128 if (!result.ok()) throwMotionError(result.error());
129 }
130
131 void cancel() {
132 auto result = handle_.cancel();
133 if (!result.ok()) throwMotionError(result.error());
134 }
135
136private:
137 MotionSequenceHandle handle_;
138};
139
140class ScriptMotionSequence {
141public:
142 explicit ScriptMotionSequence(Animation *animation)
143 : animation_(animation), sequence_(requireAnimation(animation)->motions()) {}
144
145 void append(ScriptMotionBuilder *builder) {
146 if (!builder) throw Exception("MotionSequence.append: builder is null");
147 auto taken = builder->takeDesc();
148 if (!taken.ok()) throwMotionError(taken.error());
149 auto desc = std::move(taken).value();
150 MotionBuilder bridge(animation_->motions(), desc.from, desc.to, desc.duration);
151 bridge.ease(desc.ease).delay(desc.delay).loops(desc.loops, desc.loopMode).cancelOnError(desc.cancelOnError)
152 .style(desc.style).frequency(desc.frequency).dampingRatio(desc.dampingRatio).seed(desc.seed);
153 if (desc.sink) bridge.to(*desc.sink);
154 auto scheduled = sequence_.append(std::move(bridge));
155 if (!scheduled.ok()) throwMotionError(scheduled.error());
156 }
157
158 void join(ScriptMotionBuilder *builder) {
159 if (!builder) throw Exception("MotionSequence.join: builder is null");
160 auto taken = builder->takeDesc();
161 if (!taken.ok()) throwMotionError(taken.error());
162 auto desc = std::move(taken).value();
163 MotionBuilder bridge(animation_->motions(), desc.from, desc.to, desc.duration);
164 bridge.ease(desc.ease).delay(desc.delay).loops(desc.loops, desc.loopMode).cancelOnError(desc.cancelOnError)
165 .style(desc.style).frequency(desc.frequency).dampingRatio(desc.dampingRatio).seed(desc.seed);
166 if (desc.sink) bridge.to(*desc.sink);
167 auto scheduled = sequence_.join(std::move(bridge));
168 if (!scheduled.ok()) throwMotionError(scheduled.error());
169 }
170
171 void insert(float atSeconds, ScriptMotionBuilder *builder) {
172 if (!builder) throw Exception("MotionSequence.insert: builder is null");
173 auto taken = builder->takeDesc();
174 if (!taken.ok()) throwMotionError(taken.error());
175 auto desc = std::move(taken).value();
176 MotionBuilder bridge(animation_->motions(), desc.from, desc.to, desc.duration);
177 bridge.ease(desc.ease).delay(desc.delay).loops(desc.loops, desc.loopMode).cancelOnError(desc.cancelOnError)
178 .style(desc.style).frequency(desc.frequency).dampingRatio(desc.dampingRatio).seed(desc.seed);
179 if (desc.sink) bridge.to(*desc.sink);
180 auto scheduled = sequence_.insert(atSeconds, std::move(bridge));
181 if (!scheduled.ok()) throwMotionError(scheduled.error());
182 }
183
184 void appendInterval(float seconds) {
185 auto scheduled = sequence_.appendInterval(seconds);
186 if (!scheduled.ok()) throwMotionError(scheduled.error());
187 }
188
189 float cursor() const { return sequence_.cursor(); }
190 float duration() const { return sequence_.duration(); }
191 int itemCount() const { return sequence_.itemCount(); }
192
193 ScriptMotionSequenceHandle *run() {
194 auto started = sequence_.run();
195 if (!started.ok()) throwMotionError(started.error());
196 return new ScriptMotionSequenceHandle(std::move(started).value());
197 }
198
199private:
200 Animation *animation_ = nullptr;
201 MotionSequence sequence_;
202};
203
204} // namespace
205
206void exposeMotionScriptBindings(ssq::Table &table, ssq::Class &animationClass) {
207 auto motion = table.addClass<ScriptMotionHandle>(
208 "Motion", std::function<ScriptMotionHandle *()>([]() -> ScriptMotionHandle * { return nullptr; }),
209 true);
210 motion.addFunc("isActive", &ScriptMotionHandle::isActive);
211 motion.addFunc("value", &ScriptMotionHandle::value);
212 motion.addFunc("complete", &ScriptMotionHandle::complete);
213 motion.addFunc("cancel", &ScriptMotionHandle::cancel);
214
215 auto builder = table.addClass<ScriptMotionBuilder>(
216 "MotionBuilder",
217 std::function<ScriptMotionBuilder *()>([]() -> ScriptMotionBuilder * { return nullptr; }), true);
218 builder.addFunc("ease", &ScriptMotionBuilder::ease);
219 builder.addFunc("delay", &ScriptMotionBuilder::delay);
220 builder.addFunc("loops", &ScriptMotionBuilder::loops);
221 builder.addFunc("cancelOnError", &ScriptMotionBuilder::cancelOnError);
222 builder.addFunc("frequency", &ScriptMotionBuilder::frequency);
223 builder.addFunc("dampingRatio", &ScriptMotionBuilder::dampingRatio);
224 builder.addFunc("seed", &ScriptMotionBuilder::seed);
225 builder.addFunc("run", &ScriptMotionBuilder::run);
226
227 auto seqHandle = table.addClass<ScriptMotionSequenceHandle>(
228 "MotionSequenceHandle",
229 std::function<ScriptMotionSequenceHandle *()>([]() -> ScriptMotionSequenceHandle * { return nullptr; }),
230 true);
231 seqHandle.addFunc("isActive", &ScriptMotionSequenceHandle::isActive);
232 seqHandle.addFunc("childCount", &ScriptMotionSequenceHandle::childCount);
233 seqHandle.addFunc("complete", &ScriptMotionSequenceHandle::complete);
234 seqHandle.addFunc("cancel", &ScriptMotionSequenceHandle::cancel);
235
236 auto seq = table.addClass<ScriptMotionSequence>(
237 "MotionSequence",
238 std::function<ScriptMotionSequence *()>([]() -> ScriptMotionSequence * { return nullptr; }), true);
239 seq.addFunc("append", &ScriptMotionSequence::append);
240 seq.addFunc("join", &ScriptMotionSequence::join);
241 seq.addFunc("insert", &ScriptMotionSequence::insert);
242 seq.addFunc("appendInterval", &ScriptMotionSequence::appendInterval);
243 seq.addFunc("cursor", &ScriptMotionSequence::cursor);
244 seq.addFunc("duration", &ScriptMotionSequence::duration);
245 seq.addFunc("itemCount", &ScriptMotionSequence::itemCount);
246 seq.addFunc("run", &ScriptMotionSequence::run);
247
248 animationClass.addFunc(
249 "newMotion",
250 std::function<ScriptMotionBuilder *(Animation *, float, float, float)>(
251 [](Animation *self, float from, float to, float duration) -> ScriptMotionBuilder * {
252 return new ScriptMotionBuilder(self, from, to, duration);
253 }));
254 animationClass.addFunc(
255 "newMotionPunch",
256 std::function<ScriptMotionBuilder *(Animation *, float, float, float)>(
257 [](Animation *self, float from, float strength, float duration) -> ScriptMotionBuilder * {
258 auto *b = new ScriptMotionBuilder(self, from, strength, duration);
259 b->stylePunch();
260 return b;
261 }));
262 animationClass.addFunc(
263 "newMotionShake",
264 std::function<ScriptMotionBuilder *(Animation *, float, float, float)>(
265 [](Animation *self, float from, float strength, float duration) -> ScriptMotionBuilder * {
266 auto *b = new ScriptMotionBuilder(self, from, strength, duration);
267 b->styleShake();
268 return b;
269 }));
270 animationClass.addFunc(
271 "newMotionSequence",
272 std::function<ScriptMotionSequence *(Animation *)>(
273 [](Animation *self) -> ScriptMotionSequence * { return new ScriptMotionSequence(self); }));
274 animationClass.addFunc(
275 "ensureMotionCapacity",
276 std::function<void(Animation *, int)>(
277 [](Animation *self, int count) {
278 if (!self) throw Exception("ensureMotionCapacity: Animation is null");
279 if (count < 0) throw Exception("ensureMotionCapacity: count must be >= 0");
280 self->ensureMotionCapacity(static_cast<std::size_t>(count));
281 }));
282 animationClass.addFunc(
283 "getMotionFloatCapacity",
284 std::function<int(Animation *)>(
285 [](Animation *self) -> int {
286 if (!self) throw Exception("getMotionFloatCapacity: Animation is null");
287 return static_cast<int>(self->getMotionFloatCapacity());
288 }));
289 animationClass.addFunc(
290 "getMotionFloatFreeCount",
291 std::function<int(Animation *)>(
292 [](Animation *self) -> int {
293 if (!self) throw Exception("getMotionFloatFreeCount: Animation is null");
294 return static_cast<int>(self->getMotionFloatFreeCount());
295 }));
296}
297
298} // namespace eve::animation
double value
float duration
std::string from
scene::NodeDesc desc
std::uint32_t spawned
HexCoordinates to
Cell the unit walks towards on this segment.
Definition HexUnits.cpp:64
bool scheduled
TokenKind kind
MeleePoint3 b
Definition MeleeHit.cpp:41
Fluent LitMotion-style builder that commits into MotionRuntime.
Dense motion storage advanced by Animation::advance(SimulationStep).
Squirrel GC wrappers for Motion builder / handle / sequence.
Lean LitMotion-style sequence: Append / Join / Insert / AppendInterval.
LitMotion-style typed motion handles, values, and sink interfaces.
std::weak_ptr< Run > run
Definition OnnxGpgpu.cpp:25
std::uint32_t seed
Definition PointSet.cpp:807
PrimitiveHandle handle
std::uint32_t count
std::size_t cursor
A structured explanation of a failed, degraded, or noteworthy result.
Definition Diagnostic.h:94
const std::string & message() const noexcept
Human-readable explanation.
Definition Diagnostic.h:147
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
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
Animation module — tween factory + 2D sprite-sheet / Spine + 3D skeletal playback (player / state mac...
Definition Animation.h:80
std::size_t getMotionFloatFreeCount() const noexcept
Returns the motion float free count.
Definition Animation.h:343
std::size_t getMotionFloatCapacity() const noexcept
Returns the motion float capacity.
Definition Animation.h:339
void ensureMotionCapacity(std::size_t floatCount)
Pre-size motion float pool for churn-free spawn (Phase 4).
Definition Animation.h:337
MotionLoopMode
Loop behaviour after a cycle completes.
Definition MotionTypes.h:68
@ Restart
Jump back to start each cycle.
@ Yoyo
Alternate direction each cycle.
void exposeMotionScriptBindings(ssq::Table &table, ssq::Class &animationClass)
Register Motion / MotionSequence script types and Animation factories.
@ Punch
Finite damped sine punch about from.
@ Shake
Punch with per-axis deterministic random sign.
bool enabled
bool started
Definition Graphics.cpp:183