载入中...
搜索中...
未找到
MotionSequence.cpp
浏览该文件的文档.
2
3#include "common/Diagnostic.h"
4#include "common/Status.h"
5
6#include <algorithm>
7#include <cmath>
8#include <utility>
9
10namespace eve::animation {
11namespace {
12
13[[nodiscard]] eve::Result<void> okApplied() {
15}
16
17[[nodiscard]] eve::Diagnostic badArg(const char *message) {
19}
20
21[[nodiscard]] eve::Diagnostic precondition(const char *message) {
23}
24
25} // namespace
26
28 : runtime_(runtime), children_(std::move(children)) {}
29
30bool MotionSequenceHandle::isActive() const noexcept {
31 if (!runtime_) return false;
32 for (const MotionHandle &h : children_) {
33 if (runtime_->isActive(h)) return true;
34 }
35 return false;
36}
37
39 if (index < 0 || index >= static_cast<int>(children_.size())) return {};
40 return children_[static_cast<std::size_t>(index)];
41}
42
44 if (!runtime_) return eve::Result<void>::failure(precondition("MotionSequenceHandle.complete: no runtime"));
45 for (const MotionHandle &h : children_) {
46 if (!runtime_->isActive(h)) continue;
47 auto r = runtime_->complete(h);
48 if (!r.ok()) return r;
49 }
50 return okApplied();
51}
52
54 if (!runtime_) return eve::Result<void>::failure(precondition("MotionSequenceHandle.cancel: no runtime"));
55 for (const MotionHandle &h : children_) {
56 if (!runtime_->isActive(h)) continue;
57 auto r = runtime_->cancel(h);
58 if (!r.ok()) return r;
59 }
60 return okApplied();
61}
62
63MotionSequence::MotionSequence(MotionRuntime &runtime) : runtime_(runtime) {}
64
65eve::Result<float> MotionSequence::spanOf(float delay, float duration, int loops) {
66 if (!(delay >= 0.f) || !std::isfinite(delay))
67 return eve::Result<float>::failure(badArg("MotionSequence: delay must be finite and >= 0"));
68 if (!(duration >= 0.f) || !std::isfinite(duration))
69 return eve::Result<float>::failure(badArg("MotionSequence: duration must be finite and >= 0"));
70 if (loops < 0)
72 badArg("MotionSequence: infinite loops (-1) cannot be scheduled"));
73 if (loops == 0)
74 return eve::Result<float>::failure(badArg("MotionSequence: loops must be >= 1"));
75 return eve::Result<float>::success(delay + duration * static_cast<float>(loops));
76}
77
78eve::Result<void> MotionSequence::schedule(float start, float span, Item item) {
79 if (!(start >= 0.f) || !std::isfinite(start))
80 return eve::Result<void>::failure(badArg("MotionSequence: start time must be finite and >= 0"));
81 if (!(span >= 0.f) || !std::isfinite(span))
82 return eve::Result<void>::failure(badArg("MotionSequence: span must be finite and >= 0"));
83 item.start = start;
84 items_.push_back(std::move(item));
85 duration_ = std::max(duration_, start + span);
86 return okApplied();
87}
88
89eve::Result<void> MotionSequence::appendAtCursor(Item item, float delay, float duration, int loops) {
90 auto span = spanOf(delay, duration, loops);
91 if (!span.ok()) return eve::Result<void>::failure(span.status());
92 const float start = cursor_;
93 auto scheduled = schedule(start, span.value(), std::move(item));
94 if (!scheduled.ok()) return scheduled;
95 lastAppendStart_ = start;
96 hasAppend_ = true;
97 cursor_ = start + span.value();
98 return okApplied();
99}
100
101eve::Result<void> MotionSequence::joinAtLast(Item item, float delay, float duration, int loops) {
102 auto span = spanOf(delay, duration, loops);
103 if (!span.ok()) return eve::Result<void>::failure(span.status());
104 const float start = hasAppend_ ? lastAppendStart_ : cursor_;
105 auto scheduled = schedule(start, span.value(), std::move(item));
106 if (!scheduled.ok()) return scheduled;
107 cursor_ = std::max(cursor_, start + span.value());
108 return okApplied();
109}
110
111eve::Result<void> MotionSequence::insertAt(float at, Item item, float delay, float duration, int loops) {
112 auto span = spanOf(delay, duration, loops);
113 if (!span.ok()) return eve::Result<void>::failure(span.status());
114 auto scheduled = schedule(at, span.value(), std::move(item));
115 if (!scheduled.ok()) return scheduled;
116 cursor_ = std::max(cursor_, at + span.value());
117 return okApplied();
118}
119
121 if (&builder.runtime() != &runtime_)
122 return eve::Result<void>::failure(badArg("MotionSequence.append: builder runtime mismatch"));
123 auto taken = builder.takeDesc();
124 if (!taken.ok()) return eve::Result<void>::failure(taken.status());
125 auto desc = std::move(taken).value();
126 const float delay = desc.delay;
127 const float duration = desc.duration;
128 const int loops = desc.loops;
129 Item item;
130 item.kind = Kind::Float;
131 item.floatDesc = std::move(desc);
132 return appendAtCursor(std::move(item), delay, duration, loops);
133}
134
136 if (&builder.runtime() != &runtime_)
137 return eve::Result<void>::failure(badArg("MotionSequence.append: builder runtime mismatch"));
138 auto taken = builder.takeDesc();
139 if (!taken.ok()) return eve::Result<void>::failure(taken.status());
140 auto desc = std::move(taken).value();
141 const float delay = desc.delay;
142 const float duration = desc.duration;
143 const int loops = desc.loops;
144 Item item;
145 item.kind = Kind::Vec2;
146 item.vec2Desc = std::move(desc);
147 return appendAtCursor(std::move(item), delay, duration, loops);
148}
149
151 if (&builder.runtime() != &runtime_)
152 return eve::Result<void>::failure(badArg("MotionSequence.append: builder runtime mismatch"));
153 auto taken = builder.takeDesc();
154 if (!taken.ok()) return eve::Result<void>::failure(taken.status());
155 auto desc = std::move(taken).value();
156 const float delay = desc.delay;
157 const float duration = desc.duration;
158 const int loops = desc.loops;
159 Item item;
160 item.kind = Kind::Vec3;
161 item.vec3Desc = std::move(desc);
162 return appendAtCursor(std::move(item), delay, duration, loops);
163}
164
166 if (&builder.runtime() != &runtime_)
167 return eve::Result<void>::failure(badArg("MotionSequence.join: builder runtime mismatch"));
168 auto taken = builder.takeDesc();
169 if (!taken.ok()) return eve::Result<void>::failure(taken.status());
170 auto desc = std::move(taken).value();
171 const float delay = desc.delay;
172 const float duration = desc.duration;
173 const int loops = desc.loops;
174 Item item;
175 item.kind = Kind::Float;
176 item.floatDesc = std::move(desc);
177 return joinAtLast(std::move(item), delay, duration, loops);
178}
179
181 if (&builder.runtime() != &runtime_)
182 return eve::Result<void>::failure(badArg("MotionSequence.join: builder runtime mismatch"));
183 auto taken = builder.takeDesc();
184 if (!taken.ok()) return eve::Result<void>::failure(taken.status());
185 auto desc = std::move(taken).value();
186 const float delay = desc.delay;
187 const float duration = desc.duration;
188 const int loops = desc.loops;
189 Item item;
190 item.kind = Kind::Vec2;
191 item.vec2Desc = std::move(desc);
192 return joinAtLast(std::move(item), delay, duration, loops);
193}
194
196 if (&builder.runtime() != &runtime_)
197 return eve::Result<void>::failure(badArg("MotionSequence.join: builder runtime mismatch"));
198 auto taken = builder.takeDesc();
199 if (!taken.ok()) return eve::Result<void>::failure(taken.status());
200 auto desc = std::move(taken).value();
201 const float delay = desc.delay;
202 const float duration = desc.duration;
203 const int loops = desc.loops;
204 Item item;
205 item.kind = Kind::Vec3;
206 item.vec3Desc = std::move(desc);
207 return joinAtLast(std::move(item), delay, duration, loops);
208}
209
211 if (&builder.runtime() != &runtime_)
212 return eve::Result<void>::failure(badArg("MotionSequence.insert: builder runtime mismatch"));
213 auto taken = builder.takeDesc();
214 if (!taken.ok()) return eve::Result<void>::failure(taken.status());
215 auto desc = std::move(taken).value();
216 const float delay = desc.delay;
217 const float duration = desc.duration;
218 const int loops = desc.loops;
219 Item item;
220 item.kind = Kind::Float;
221 item.floatDesc = std::move(desc);
222 return insertAt(atSeconds, std::move(item), delay, duration, loops);
223}
224
226 if (&builder.runtime() != &runtime_)
227 return eve::Result<void>::failure(badArg("MotionSequence.insert: builder runtime mismatch"));
228 auto taken = builder.takeDesc();
229 if (!taken.ok()) return eve::Result<void>::failure(taken.status());
230 auto desc = std::move(taken).value();
231 const float delay = desc.delay;
232 const float duration = desc.duration;
233 const int loops = desc.loops;
234 Item item;
235 item.kind = Kind::Vec2;
236 item.vec2Desc = std::move(desc);
237 return insertAt(atSeconds, std::move(item), delay, duration, loops);
238}
239
241 if (&builder.runtime() != &runtime_)
242 return eve::Result<void>::failure(badArg("MotionSequence.insert: builder runtime mismatch"));
243 auto taken = builder.takeDesc();
244 if (!taken.ok()) return eve::Result<void>::failure(taken.status());
245 auto desc = std::move(taken).value();
246 const float delay = desc.delay;
247 const float duration = desc.duration;
248 const int loops = desc.loops;
249 Item item;
250 item.kind = Kind::Vec3;
251 item.vec3Desc = std::move(desc);
252 return insertAt(atSeconds, std::move(item), delay, duration, loops);
253}
254
256 if (!(seconds >= 0.f) || !std::isfinite(seconds))
257 return eve::Result<void>::failure(badArg("MotionSequence.appendInterval: seconds must be finite and >= 0"));
258 cursor_ += seconds;
259 duration_ = std::max(duration_, cursor_);
260 return okApplied();
261}
262
264 std::vector<MotionHandle> children;
265 children.reserve(items_.size());
266
267 for (Item &item : items_) {
268 switch (item.kind) {
269 case Kind::Float: {
270 item.floatDesc.delay += item.start;
271 auto spawned = runtime_.spawnFloat(item.floatDesc);
273 children.push_back(spawned.value());
274 break;
275 }
276 case Kind::Vec2: {
277 item.vec2Desc.delay += item.start;
278 auto spawned = runtime_.spawnVec2(item.vec2Desc);
280 children.push_back(spawned.value());
281 break;
282 }
283 case Kind::Vec3: {
284 item.vec3Desc.delay += item.start;
285 auto spawned = runtime_.spawnVec3(item.vec3Desc);
287 children.push_back(spawned.value());
288 break;
289 }
290 }
291 }
292
293 items_.clear();
294 cursor_ = 0.f;
295 duration_ = 0.f;
296 lastAppendStart_ = 0.f;
297 hasAppend_ = false;
299}
300
301} // namespace eve::animation
Duration start
float duration
Stable, structured diagnostics shared by engine modules.
scene::NodeDesc desc
std::string message
std::uint32_t spawned
double r
int h
bool scheduled
Lean LitMotion-style sequence: Append / Join / Insert / AppendInterval.
Structured operation status used by the common Result foundation.
std::vector< ecs::EntityHandle > schedule
The round's activation queue, resolved against the target battle.
int children
Definition TreeMesh.cpp:295
uint32_t index
std::size_t at
A structured explanation of a failed, degraded, or noteworthy result.
Definition Diagnostic.h:94
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
Configure then bind/run a float motion into a MotionRuntime.
Owns typed motion slots and applies SimulationStep updates.
bool isActive(MotionHandle handle) const noexcept
eve::Result< MotionHandle > spawnFloat(const FloatDesc &desc)
eve::Result< MotionHandle > spawnVec2(const Vec2Desc &desc)
eve::Result< void > complete(MotionHandle handle)
eve::Result< MotionHandle > spawnVec3(const Vec3Desc &desc)
eve::Result< void > cancel(MotionHandle handle)
Playback handle for a sequence's child motions.
MotionSequenceHandle()=default
Motion sequence handle.
MotionHandle child(int index) const
Child.
eve::Result< void > complete()
Complete every still-active child (fires onComplete).
eve::Result< void > cancel()
Cancel every still-active child (fires onCancel).
bool isActive() const noexcept
True when active.
eve::Result< void > append(MotionBuilder &&builder)
Append.
eve::Result< void > appendInterval(float seconds)
Append interval.
eve::Result< MotionSequenceHandle > run()
Spawn every scheduled item into the runtime.
eve::Result< void > insert(float atSeconds, MotionBuilder &&builder)
Inserts .
MotionSequence(MotionRuntime &runtime)
Motion sequence.
float duration() const noexcept
Duration.
eve::Result< void > join(MotionBuilder &&builder)
Join.
Generation-checked slot identity for a live motion.
Definition MotionTypes.h:20