载入中...
搜索中...
未找到
Tween.cpp
浏览该文件的文档.
1#include "animation/Tween.h"
2
5
6#include "common/Exception.h"
7
8#include <algorithm>
9#include <cmath>
10
11#ifndef M_PI
12#define M_PI 3.14159265358979323846
13#endif
14
15namespace eve::animation {
16
18
20 if (owner_) owner_->unregisterTween(this);
21}
22
23Tween::Track &Tween::ensureTrack(const std::string &name) {
24 auto it = tracks_.find(name);
25 if (it != tracks_.end()) return it->second;
26 order_.push_back(name);
27 return tracks_[name];
28}
29
30const Tween::Track *Tween::findTrack(const std::string &name) const {
31 auto it = tracks_.find(name);
32 if (it == tracks_.end()) return nullptr;
33 return &it->second;
34}
35
36void Tween::setFrom(const std::string &name, float value) {
37 Track &tr = ensureTrack(name);
38 tr.from = value;
39 tr.hasFrom = true;
40 tr.isAngle = false;
41 if (!tr.resolved) tr.current = value;
42}
43
44void Tween::setTo(const std::string &name, float value) {
45 Track &tr = ensureTrack(name);
46 tr.to = value;
47 tr.endMode = EndMode::Absolute;
48 tr.isAngle = false;
49 tr.resolved = false;
50}
51
52void Tween::setDelta(const std::string &name, float delta) {
53 Track &tr = ensureTrack(name);
54 tr.delta = delta;
55 tr.endMode = EndMode::Delta;
56 tr.isAngle = false;
57 tr.resolved = false;
58}
59
60void Tween::setFromAngle(const std::string &name, float radians) {
61 Track &tr = ensureTrack(name);
62 tr.from = radians;
63 tr.hasFrom = true;
64 tr.isAngle = true;
65 if (!tr.resolved) tr.current = radians;
66}
67
68void Tween::setToAngle(const std::string &name, float radians) {
69 Track &tr = ensureTrack(name);
70 tr.to = radians;
71 tr.endMode = EndMode::Absolute;
72 tr.isAngle = true;
73 tr.resolved = false;
74}
75
76void Tween::setDeltaAngle(const std::string &name, float deltaRadians) {
77 Track &tr = ensureTrack(name);
78 tr.delta = deltaRadians;
79 tr.endMode = EndMode::Delta;
80 tr.isAngle = true;
81 tr.resolved = false;
82}
83
84bool Tween::has(const std::string &name) const { return findTrack(name) != nullptr; }
85
86float Tween::get(const std::string &name) const {
87 const Track *tr = findTrack(name);
88 if (!tr) throw Exception("Tween.get: unknown property '%s'", name.c_str());
89 return tr->current;
90}
91
92float Tween::getFrom(const std::string &name) const {
93 const Track *tr = findTrack(name);
94 if (!tr) throw Exception("Tween.getFrom: unknown property '%s'", name.c_str());
95 return tr->from;
96}
97
98float Tween::getTo(const std::string &name) const {
99 const Track *tr = findTrack(name);
100 if (!tr) throw Exception("Tween.getTo: unknown property '%s'", name.c_str());
101 if (tr->endMode == EndMode::Delta && !tr->resolved) return tr->from + tr->delta;
102 return tr->to;
103}
104
105float Tween::getDelta(const std::string &name) const {
106 const Track *tr = findTrack(name);
107 if (!tr) throw Exception("Tween.getDelta: unknown property '%s'", name.c_str());
108 if (tr->endMode == EndMode::Delta) return tr->delta;
109 return tr->to - tr->from;
110}
111
112void Tween::setDuration(float seconds) {
113 if (seconds < 0.f) throw Exception("Tween.setDuration: duration must be >= 0");
114 duration_ = seconds;
115}
116
117void Tween::setDelay(float seconds) {
118 if (seconds < 0.f) throw Exception("Tween.setDelay: delay must be >= 0");
119 delay_ = seconds;
120}
121
122void Tween::setEase(const std::string &kind) {
123 // Validate against known kinds (same set as Math.ease).
124 (void)ease(0.5f, kind);
125 ease_ = kind.empty() ? "linear" : kind;
126}
127
129 if (count < -1) count = -1;
130 if (count == 0) count = 1;
131 repeat_ = count;
132}
133
134float Tween::clamp01(float t) { return std::clamp(t, 0.f, 1.f); }
135
136float Tween::lerpAngle(float a, float b, float t) {
137 float diff = b - a;
138 while (diff > float(M_PI)) diff -= float(2.0 * M_PI);
139 while (diff < -float(M_PI)) diff += float(2.0 * M_PI);
140 return a + diff * t;
141}
142
143float Tween::ease(float t, const std::string &kind) {
144 t = clamp01(t);
145 if (kind == "linear" || kind.empty()) return t;
146 if (kind == "inQuad") return t * t;
147 if (kind == "outQuad") return 1.f - (1.f - t) * (1.f - t);
148 if (kind == "inOutQuad")
149 return t < 0.5f ? 2.f * t * t : 1.f - std::pow(-2.f * t + 2.f, 2.f) * 0.5f;
150 if (kind == "inCubic") return t * t * t;
151 if (kind == "outCubic") return 1.f - std::pow(1.f - t, 3.f);
152 if (kind == "inOutCubic")
153 return t < 0.5f ? 4.f * t * t * t : 1.f - std::pow(-2.f * t + 2.f, 3.f) * 0.5f;
154 if (kind == "inSine") return 1.f - std::cos(t * float(M_PI) * 0.5f);
155 if (kind == "outSine") return std::sin(t * float(M_PI) * 0.5f);
156 if (kind == "inOutSine") return -(std::cos(float(M_PI) * t) - 1.f) * 0.5f;
157 if (kind == "inExpo") return t <= 0.f ? 0.f : std::pow(2.f, 10.f * t - 10.f);
158 if (kind == "outExpo") return t >= 1.f ? 1.f : 1.f - std::pow(2.f, -10.f * t);
159 if (kind == "inOutExpo") {
160 if (t <= 0.f) return 0.f;
161 if (t >= 1.f) return 1.f;
162 return t < 0.5f ? std::pow(2.f, 20.f * t - 10.f) * 0.5f
163 : (2.f - std::pow(2.f, -20.f * t + 10.f)) * 0.5f;
164 }
165 throw Exception("Tween.setEase: unknown kind '%s'", kind.c_str());
166}
167
168void Tween::resolveTracks() {
169 for (auto &kv : tracks_) {
170 Track &tr = kv.second;
171 if (!tr.hasFrom) {
172 tr.from = tr.current;
173 tr.hasFrom = true;
174 }
175 if (tr.endMode == EndMode::Delta) tr.to = tr.from + tr.delta;
176 tr.current = tr.from;
177 tr.resolved = true;
178 }
179}
180
181void Tween::applyProgress(float linearT) {
182 float t = reverse_ ? (1.f - clamp01(linearT)) : clamp01(linearT);
183 float e = ease(t, ease_);
184 for (auto &kv : tracks_) {
185 Track &tr = kv.second;
186 if (tr.isAngle)
187 tr.current = lerpAngle(tr.from, tr.to, e);
188 else
189 tr.current = tr.from + (tr.to - tr.from) * e;
190 }
191}
192
193float Tween::getProgress() const {
194 if (duration_ <= 0.f) return state_ == State::Finished ? 1.f : 0.f;
195 return clamp01(elapsed_ / duration_);
196}
197
199 float t = getProgress();
200 if (reverse_) t = 1.f - t;
201 return ease(t, ease_);
202}
203
205 resolveTracks();
206 elapsed_ = 0.f;
207 played_ = 0;
208 reverse_ = false;
209 delayLeft_ = delay_;
210 state_ = delay_ > 0.f ? State::Delayed : State::Running;
211 if (state_ == State::Running) applyProgress(0.f);
212}
213
215 if (state_ == State::Running || state_ == State::Delayed) state_ = State::Paused;
216}
217
219 if (state_ != State::Paused) return;
220 if (delayLeft_ > 0.f)
221 state_ = State::Delayed;
222 else
223 state_ = State::Running;
224}
225
227 state_ = State::Stopped;
228 delayLeft_ = 0.f;
229}
230
232 elapsed_ = 0.f;
233 played_ = 0;
234 reverse_ = false;
235 delayLeft_ = delay_;
236 state_ = State::Idle;
237 for (auto &kv : tracks_) {
238 Track &tr = kv.second;
239 tr.resolved = false;
240 if (tr.hasFrom) tr.current = tr.from;
241 }
242}
243
244void Tween::finishCycle() {
245 ++played_;
246 applyProgress(1.f);
247
248 const bool infinite = repeat_ < 0;
249 if (!infinite && played_ >= repeat_) {
250 state_ = State::Finished;
251 return;
252 }
253
254 if (yoyo_) reverse_ = !reverse_;
255 elapsed_ = 0.f;
256 // Snap to the start of the next cycle orientation.
257 applyProgress(0.f);
258 state_ = State::Running;
259}
260
261bool Tween::updateUnchecked(float dt) {
262 if (dt < 0.f) dt = 0.f;
263
264 if (state_ == State::Paused) return true;
265 if (state_ != State::Delayed && state_ != State::Running) return false;
266
267 if (state_ == State::Delayed) {
268 delayLeft_ -= dt;
269 if (delayLeft_ > 0.f) return true;
270 dt = -delayLeft_;
271 delayLeft_ = 0.f;
272 state_ = State::Running;
273 applyProgress(0.f);
274 if (dt <= 0.f) return true;
275 }
276
277 if (duration_ <= 0.f) {
278 applyProgress(1.f);
279 finishCycle();
280 return isActive();
281 }
282
283 elapsed_ += dt;
284 while (state_ == State::Running && elapsed_ >= duration_) {
285 float over = elapsed_ - duration_;
286 finishCycle();
287 if (state_ != State::Running) break;
288 elapsed_ = over;
289 }
290
291 if (state_ == State::Running) applyProgress(getProgress());
292 return isActive();
293}
294
296 auto seconds = detail::secondsForStep(step, hasLastTick_, lastTick_, "Tween");
297 if (!seconds) return eve::Result<void>::failure(seconds.status());
298 updateUnchecked(std::move(seconds).takeValue());
299 lastTick_ = step.tick;
300 hasLastTick_ = true;
302}
303
304bool Tween::update(float dt) {
305 auto step = detail::legacyStep(dt, hasLastTick_, lastTick_, "Tween");
306 if (!step) {
307 step.ignore("legacy Tween update");
308 return isActive();
309 }
310 auto result = advance(std::move(step).takeValue());
311 result.ignore("legacy Tween update");
312 return isActive();
313}
314
315float Tween::evaluate(const std::string &name, float t) const {
316 const Track *tr = findTrack(name);
317 if (!tr) throw Exception("Tween.evaluate: unknown property '%s'", name.c_str());
318
319 float from = tr->from;
320 float to = tr->endMode == EndMode::Delta && !tr->resolved ? tr->from + tr->delta : tr->to;
321 if (!tr->hasFrom && !tr->resolved) from = tr->current;
322
323 float e = ease(clamp01(t), ease_);
324 if (tr->isAngle) return lerpAngle(from, to, e);
325 return from + (to - from) * e;
326}
327
328std::string Tween::getPropertyName(int index) const {
329 if (index < 0 || index >= static_cast<int>(order_.size()))
330 throw Exception("Tween.getPropertyName: index %d out of range (count=%d)", index,
331 static_cast<int>(order_.size()));
332 return order_[static_cast<size_t>(index)];
333}
334
335} // namespace eve::animation
double value
float duration
std::string from
HexCoordinates to
Cell the unit walks towards on this segment.
Definition HexUnits.cpp:64
TokenKind kind
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float tr
#define M_PI
float t
std::uint32_t count
float step
Definition TreeMesh.cpp:314
uint32_t index
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
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
void setFrom(const std::string &name, float value)
Sets the from.
Definition Tween.cpp:36
void setDelay(float seconds)
Sets the delay.
Definition Tween.cpp:117
void start()
Starts .
Definition Tween.cpp:204
void setDeltaAngle(const std::string &name, float deltaRadians)
Sets the delta angle.
Definition Tween.cpp:76
void setToAngle(const std::string &name, float radians)
Sets the to angle.
Definition Tween.cpp:68
void setEase(const std::string &kind)
Sets the ease.
Definition Tween.cpp:122
void pause()
Pause.
Definition Tween.cpp:214
void reset()
Resets .
Definition Tween.cpp:231
float getEasedProgress() const
Eased progress used for interpolation, [0,1].
Definition Tween.cpp:198
bool update(float dt)
Advance by dt seconds; legacy facade that forwards to advance().
Definition Tween.cpp:304
void setFromAngle(const std::string &name, float radians)
Sets the from angle.
Definition Tween.cpp:60
Tween(float duration=1.f)
Tween.
Definition Tween.cpp:17
float get(const std::string &name) const
Returns the value.
Definition Tween.cpp:86
bool isActive() const
True when active.
Definition Tween.h:107
float getProgress() const
Linear progress in the current cycle, [0,1].
Definition Tween.cpp:193
void setDuration(float seconds)
Sets the duration.
Definition Tween.cpp:112
std::string getPropertyName(int index) const
Returns the property name.
Definition Tween.cpp:328
float evaluate(const std::string &name, float t) const
Sample property at linear t in [0,1] using current from/to (no state change).
Definition Tween.cpp:315
void stop()
Stops .
Definition Tween.cpp:226
float getFrom(const std::string &name) const
Returns the from.
Definition Tween.cpp:92
eve::Result< void > advance(const eve::SimulationStep &step)
Advance by one scheduler-owned deterministic step.
Definition Tween.cpp:295
void setRepeat(int count)
Play count: 1 = once (default), N = N cycles, -1 = infinite. Values < -1 are clamped to -1.
Definition Tween.cpp:128
void setDelta(const std::string &name, float delta)
Relative change: end = start + delta (resolved when start() runs).
Definition Tween.cpp:52
float getTo(const std::string &name) const
Returns the to.
Definition Tween.cpp:98
void setTo(const std::string &name, float value)
Sets the to.
Definition Tween.cpp:44
void resume()
Resume.
Definition Tween.cpp:218
float getDelta(const std::string &name) const
Returns the delta.
Definition Tween.cpp:105
bool has(const std::string &name) const
True when active.
Definition Tween.cpp:84
eve::Result< eve::SimulationStep > legacyStep(float seconds, bool hasLastTick, eve::SimulationTick lastTick, const char *owner)
Convert a legacy seconds call to the next local scheduler step.
eve::Result< float > secondsForStep(const eve::SimulationStep &step, bool hasLastTick, eve::SimulationTick lastTick, const char *owner)
Validate a scheduler step before an animation object mutates state.
One deterministic fixed-step emitted by SimulationClock.
Definition Time.h:158