Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/animation/tween.cpp
20897 views
1
/**************************************************************************/
2
/* tween.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "tween.h"
32
33
#include "scene/animation/easing_equations.h"
34
#include "scene/main/node.h"
35
#include "scene/resources/animation.h"
36
37
#define CHECK_VALID() \
38
ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); \
39
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
40
41
Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
42
{ &Linear::in, &Linear::in, &Linear::in, &Linear::in }, // Linear is the same for each easing.
43
{ &Sine::in, &Sine::out, &Sine::in_out, &Sine::out_in },
44
{ &Quint::in, &Quint::out, &Quint::in_out, &Quint::out_in },
45
{ &Quart::in, &Quart::out, &Quart::in_out, &Quart::out_in },
46
{ &Quad::in, &Quad::out, &Quad::in_out, &Quad::out_in },
47
{ &Expo::in, &Expo::out, &Expo::in_out, &Expo::out_in },
48
{ &Elastic::in, &Elastic::out, &Elastic::in_out, &Elastic::out_in },
49
{ &Cubic::in, &Cubic::out, &Cubic::in_out, &Cubic::out_in },
50
{ &Circ::in, &Circ::out, &Circ::in_out, &Circ::out_in },
51
{ &Bounce::in, &Bounce::out, &Bounce::in_out, &Bounce::out_in },
52
{ &Back::in, &Back::out, &Back::in_out, &Back::out_in },
53
{ &Spring::in, &Spring::out, &Spring::in_out, &Spring::out_in },
54
};
55
56
void Tweener::set_tween(const Ref<Tween> &p_tween) {
57
tween_id = p_tween->get_instance_id();
58
}
59
60
void Tweener::start() {
61
elapsed_time = 0;
62
finished = false;
63
}
64
65
Ref<Tween> Tweener::_get_tween() {
66
return ObjectDB::get_ref<Tween>(tween_id);
67
}
68
69
void Tweener::_finish() {
70
finished = true;
71
emit_signal(SceneStringName(finished));
72
}
73
74
void Tweener::_bind_methods() {
75
ADD_SIGNAL(MethodInfo("finished"));
76
}
77
78
void Tween::_start_tweeners() {
79
if (tweeners.is_empty()) {
80
dead = true;
81
ERR_FAIL_MSG("Tween without commands, aborting.");
82
}
83
84
for (Ref<Tweener> &tweener : tweeners[current_step]) {
85
tweener->start();
86
}
87
}
88
89
void Tween::_stop_internal(bool p_reset) {
90
running = false;
91
if (p_reset) {
92
started = false;
93
dead = false;
94
total_time = 0;
95
}
96
}
97
98
RequiredResult<PropertyTweener> Tween::tween_property(RequiredParam<const Object> rp_target, const NodePath &p_property, Variant p_to, double p_duration) {
99
EXTRACT_PARAM_OR_FAIL_V(p_target, rp_target, nullptr);
100
CHECK_VALID();
101
102
Vector<StringName> property_subnames = p_property.get_as_property_path().get_subnames();
103
#ifdef DEBUG_ENABLED
104
bool prop_valid;
105
const Variant &prop_value = p_target->get_indexed(property_subnames, &prop_valid);
106
ERR_FAIL_COND_V_MSG(!prop_valid, nullptr, vformat("The tweened property \"%s\" does not exist in object \"%s\".", p_property, p_target));
107
#else
108
const Variant &prop_value = p_target->get_indexed(property_subnames);
109
#endif
110
111
if (!Animation::validate_type_match(prop_value, p_to)) {
112
return nullptr;
113
}
114
115
Ref<PropertyTweener> tweener;
116
tweener.instantiate(p_target, property_subnames, p_to, p_duration);
117
append(tweener);
118
return tweener;
119
}
120
121
RequiredResult<IntervalTweener> Tween::tween_interval(double p_time) {
122
CHECK_VALID();
123
124
Ref<IntervalTweener> tweener;
125
tweener.instantiate(p_time);
126
append(tweener);
127
return tweener;
128
}
129
130
RequiredResult<CallbackTweener> Tween::tween_callback(const Callable &p_callback) {
131
CHECK_VALID();
132
133
Ref<CallbackTweener> tweener;
134
tweener.instantiate(p_callback);
135
append(tweener);
136
return tweener;
137
}
138
139
RequiredResult<MethodTweener> Tween::tween_method(const Callable &p_callback, const Variant p_from, Variant p_to, double p_duration) {
140
CHECK_VALID();
141
142
if (!Animation::validate_type_match(p_from, p_to)) {
143
return nullptr;
144
}
145
146
Ref<MethodTweener> tweener;
147
tweener.instantiate(p_callback, p_from, p_to, p_duration);
148
append(tweener);
149
return tweener;
150
}
151
152
RequiredResult<SubtweenTweener> Tween::tween_subtween(RequiredParam<Tween> rp_subtween) {
153
CHECK_VALID();
154
155
// Ensure that the subtween being added is not null.
156
EXTRACT_PARAM_OR_FAIL_V(p_subtween, rp_subtween, nullptr);
157
158
Ref<SubtweenTweener> tweener;
159
tweener.instantiate(p_subtween);
160
161
// Remove the tween from its parent tree, if it has one.
162
// If the user created this tween without a parent tree attached,
163
// then this step isn't necessary.
164
if (tweener->subtween->parent_tree != nullptr) {
165
tweener->subtween->parent_tree->remove_tween(tweener->subtween);
166
}
167
subtweens.push_back(p_subtween);
168
append(tweener);
169
return tweener;
170
}
171
172
void Tween::append(Ref<Tweener> p_tweener) {
173
p_tweener->set_tween(this);
174
175
if (parallel_enabled) {
176
current_step = MAX(current_step, 0);
177
} else {
178
current_step++;
179
}
180
parallel_enabled = default_parallel;
181
182
tweeners.resize(current_step + 1);
183
tweeners[current_step].push_back(p_tweener);
184
}
185
186
void Tween::stop() {
187
_stop_internal(true);
188
}
189
190
void Tween::pause() {
191
_stop_internal(false);
192
}
193
194
void Tween::play() {
195
ERR_FAIL_COND_MSG(!valid, "Tween invalid. Either finished or created outside scene tree.");
196
ERR_FAIL_COND_MSG(dead, "Can't play finished Tween, use stop() first to reset its state.");
197
running = true;
198
}
199
200
void Tween::kill() {
201
running = false; // For the sake of is_running().
202
valid = false;
203
dead = true;
204
205
// Kill all subtweens of this tween.
206
for (Ref<Tween> &st : subtweens) {
207
st->kill();
208
}
209
}
210
211
bool Tween::is_running() {
212
return running;
213
}
214
215
bool Tween::is_valid() {
216
return valid;
217
}
218
219
void Tween::clear() {
220
valid = false;
221
tweeners.clear();
222
}
223
224
RequiredResult<Tween> Tween::bind_node(RequiredParam<const Node> rp_node) {
225
EXTRACT_PARAM_OR_FAIL_V(p_node, rp_node, this);
226
227
bound_node = p_node->get_instance_id();
228
is_bound = true;
229
return this;
230
}
231
232
RequiredResult<Tween> Tween::set_process_mode(TweenProcessMode p_mode) {
233
process_mode = p_mode;
234
return this;
235
}
236
237
Tween::TweenProcessMode Tween::get_process_mode() const {
238
return process_mode;
239
}
240
241
RequiredResult<Tween> Tween::set_pause_mode(TweenPauseMode p_mode) {
242
pause_mode = p_mode;
243
return this;
244
}
245
246
Tween::TweenPauseMode Tween::get_pause_mode() const {
247
return pause_mode;
248
}
249
250
RequiredResult<Tween> Tween::set_ignore_time_scale(bool p_ignore) {
251
ignore_time_scale = p_ignore;
252
return this;
253
}
254
255
bool Tween::is_ignoring_time_scale() const {
256
return ignore_time_scale;
257
}
258
259
RequiredResult<Tween> Tween::set_parallel(bool p_parallel) {
260
default_parallel = p_parallel;
261
parallel_enabled = p_parallel;
262
return this;
263
}
264
265
RequiredResult<Tween> Tween::set_loops(int p_loops) {
266
loops = p_loops;
267
return this;
268
}
269
270
int Tween::get_loops_left() const {
271
if (loops <= 0) {
272
return -1; // Infinite loop.
273
} else {
274
return loops - loops_done;
275
}
276
}
277
278
RequiredResult<Tween> Tween::set_speed_scale(float p_speed) {
279
speed_scale = p_speed;
280
return this;
281
}
282
283
RequiredResult<Tween> Tween::set_trans(TransitionType p_trans) {
284
default_transition = p_trans;
285
return this;
286
}
287
288
Tween::TransitionType Tween::get_trans() const {
289
return default_transition;
290
}
291
292
RequiredResult<Tween> Tween::set_ease(EaseType p_ease) {
293
default_ease = p_ease;
294
return this;
295
}
296
297
Tween::EaseType Tween::get_ease() const {
298
return default_ease;
299
}
300
301
RequiredResult<Tween> Tween::parallel() {
302
parallel_enabled = true;
303
return this;
304
}
305
306
RequiredResult<Tween> Tween::chain() {
307
parallel_enabled = false;
308
return this;
309
}
310
311
bool Tween::custom_step(double p_delta) {
312
ERR_FAIL_COND_V_MSG(in_step, true, "Can't call custom_step() during another Tween step.");
313
314
bool r = running;
315
running = true;
316
bool ret = step(p_delta);
317
running = running && r; // Running might turn false when Tween finished.
318
return ret;
319
}
320
321
bool Tween::step(double p_delta) {
322
if (dead) {
323
return false;
324
}
325
326
if (is_bound) {
327
Node *node = get_bound_node();
328
if (node) {
329
if (!node->is_inside_tree()) {
330
return true;
331
}
332
} else {
333
return false;
334
}
335
}
336
337
if (!running) {
338
return true;
339
}
340
in_step = true;
341
342
if (!started) {
343
if (tweeners.is_empty()) {
344
String tween_id;
345
Node *node = get_bound_node();
346
if (node) {
347
tween_id = vformat("Tween (bound to %s)", node->is_inside_tree() ? (String)node->get_path() : (String)node->get_name());
348
} else {
349
tween_id = to_string();
350
}
351
in_step = false;
352
ERR_FAIL_V_MSG(false, tween_id + ": started with no Tweeners.");
353
}
354
current_step = 0;
355
loops_done = 0;
356
total_time = 0;
357
_start_tweeners();
358
started = true;
359
}
360
361
double rem_delta = p_delta * speed_scale;
362
bool step_active = false;
363
total_time += rem_delta;
364
365
#ifdef DEBUG_ENABLED
366
double initial_delta = rem_delta;
367
bool potential_infinite = false;
368
#endif
369
370
while (running && rem_delta > 0) {
371
double step_delta = rem_delta;
372
step_active = false;
373
374
for (Ref<Tweener> &tweener : tweeners[current_step]) {
375
// Modified inside Tweener.step().
376
double temp_delta = rem_delta;
377
// Turns to true if any Tweener returns true (i.e. is still not finished).
378
step_active = tweener->step(temp_delta) || step_active;
379
step_delta = MIN(temp_delta, step_delta);
380
}
381
382
rem_delta = step_delta;
383
384
if (!step_active) {
385
emit_signal(SNAME("step_finished"), current_step);
386
current_step++;
387
388
if (current_step == (int)tweeners.size()) {
389
loops_done++;
390
if (loops_done == loops) {
391
running = false;
392
dead = true;
393
emit_signal(SceneStringName(finished));
394
break;
395
} else {
396
emit_signal(SNAME("loop_finished"), loops_done);
397
current_step = 0;
398
_start_tweeners();
399
#ifdef DEBUG_ENABLED
400
if (loops <= 0 && Math::is_equal_approx(rem_delta, initial_delta)) {
401
if (!potential_infinite) {
402
potential_infinite = true;
403
} else {
404
// Looped twice without using any time, this is 100% certain infinite loop.
405
in_step = false;
406
ERR_FAIL_V_MSG(false, "Infinite loop detected. Check set_loops() description for more info.");
407
}
408
}
409
#endif
410
}
411
} else {
412
_start_tweeners();
413
}
414
}
415
}
416
in_step = false;
417
return true;
418
}
419
420
bool Tween::can_process(bool p_tree_paused) const {
421
if (is_bound && pause_mode == TWEEN_PAUSE_BOUND) {
422
Node *node = get_bound_node();
423
if (node) {
424
return node->is_inside_tree() && node->can_process();
425
}
426
}
427
428
return !p_tree_paused || pause_mode == TWEEN_PAUSE_PROCESS;
429
}
430
431
Node *Tween::get_bound_node() const {
432
if (is_bound) {
433
return ObjectDB::get_instance<Node>(bound_node);
434
} else {
435
return nullptr;
436
}
437
}
438
439
double Tween::get_total_time() const {
440
return total_time;
441
}
442
443
real_t Tween::run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t p_time, real_t p_initial, real_t p_delta, real_t p_duration) {
444
if (p_duration == 0) {
445
// Special case to avoid dividing by 0 in equations.
446
return p_initial + p_delta;
447
}
448
449
interpolater func = interpolaters[p_trans_type][p_ease_type];
450
return func(p_time, p_initial, p_delta, p_duration);
451
}
452
453
Variant Tween::interpolate_variant(const Variant &p_initial_val, const Variant &p_delta_val, double p_time, double p_duration, TransitionType p_trans, EaseType p_ease) {
454
ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant());
455
ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant());
456
457
Variant ret = Animation::add_variant(p_initial_val, p_delta_val);
458
ret = Animation::interpolate_variant(p_initial_val, ret, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration), p_initial_val.is_string());
459
return ret;
460
}
461
462
String Tween::_to_string() {
463
String ret = Object::_to_string();
464
Node *node = get_bound_node();
465
if (node) {
466
ret += vformat(" (bound to %s)", node->get_name());
467
}
468
return ret;
469
}
470
471
void Tween::_bind_methods() {
472
ClassDB::bind_method(D_METHOD("tween_property", "object", "property", "final_val", "duration"), &Tween::tween_property);
473
ClassDB::bind_method(D_METHOD("tween_interval", "time"), &Tween::tween_interval);
474
ClassDB::bind_method(D_METHOD("tween_callback", "callback"), &Tween::tween_callback);
475
ClassDB::bind_method(D_METHOD("tween_method", "method", "from", "to", "duration"), &Tween::tween_method);
476
ClassDB::bind_method(D_METHOD("tween_subtween", "subtween"), &Tween::tween_subtween);
477
478
ClassDB::bind_method(D_METHOD("custom_step", "delta"), &Tween::custom_step);
479
ClassDB::bind_method(D_METHOD("stop"), &Tween::stop);
480
ClassDB::bind_method(D_METHOD("pause"), &Tween::pause);
481
ClassDB::bind_method(D_METHOD("play"), &Tween::play);
482
ClassDB::bind_method(D_METHOD("kill"), &Tween::kill);
483
ClassDB::bind_method(D_METHOD("get_total_elapsed_time"), &Tween::get_total_time);
484
485
ClassDB::bind_method(D_METHOD("is_running"), &Tween::is_running);
486
ClassDB::bind_method(D_METHOD("is_valid"), &Tween::is_valid);
487
ClassDB::bind_method(D_METHOD("bind_node", "node"), &Tween::bind_node);
488
ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Tween::set_process_mode);
489
ClassDB::bind_method(D_METHOD("set_pause_mode", "mode"), &Tween::set_pause_mode);
490
ClassDB::bind_method(D_METHOD("set_ignore_time_scale", "ignore"), &Tween::set_ignore_time_scale, DEFVAL(true));
491
492
ClassDB::bind_method(D_METHOD("set_parallel", "parallel"), &Tween::set_parallel, DEFVAL(true));
493
ClassDB::bind_method(D_METHOD("set_loops", "loops"), &Tween::set_loops, DEFVAL(0));
494
ClassDB::bind_method(D_METHOD("get_loops_left"), &Tween::get_loops_left);
495
ClassDB::bind_method(D_METHOD("set_speed_scale", "speed"), &Tween::set_speed_scale);
496
ClassDB::bind_method(D_METHOD("set_trans", "trans"), &Tween::set_trans);
497
ClassDB::bind_method(D_METHOD("set_ease", "ease"), &Tween::set_ease);
498
499
ClassDB::bind_method(D_METHOD("parallel"), &Tween::parallel);
500
ClassDB::bind_method(D_METHOD("chain"), &Tween::chain);
501
502
ClassDB::bind_static_method("Tween", D_METHOD("interpolate_value", "initial_value", "delta_value", "elapsed_time", "duration", "trans_type", "ease_type"), &Tween::interpolate_variant);
503
504
ADD_SIGNAL(MethodInfo("step_finished", PropertyInfo(Variant::INT, "idx")));
505
ADD_SIGNAL(MethodInfo("loop_finished", PropertyInfo(Variant::INT, "loop_count")));
506
ADD_SIGNAL(MethodInfo("finished"));
507
508
BIND_ENUM_CONSTANT(TWEEN_PROCESS_PHYSICS);
509
BIND_ENUM_CONSTANT(TWEEN_PROCESS_IDLE);
510
511
BIND_ENUM_CONSTANT(TWEEN_PAUSE_BOUND);
512
BIND_ENUM_CONSTANT(TWEEN_PAUSE_STOP);
513
BIND_ENUM_CONSTANT(TWEEN_PAUSE_PROCESS);
514
515
BIND_ENUM_CONSTANT(TRANS_LINEAR);
516
BIND_ENUM_CONSTANT(TRANS_SINE);
517
BIND_ENUM_CONSTANT(TRANS_QUINT);
518
BIND_ENUM_CONSTANT(TRANS_QUART);
519
BIND_ENUM_CONSTANT(TRANS_QUAD);
520
BIND_ENUM_CONSTANT(TRANS_EXPO);
521
BIND_ENUM_CONSTANT(TRANS_ELASTIC);
522
BIND_ENUM_CONSTANT(TRANS_CUBIC);
523
BIND_ENUM_CONSTANT(TRANS_CIRC);
524
BIND_ENUM_CONSTANT(TRANS_BOUNCE);
525
BIND_ENUM_CONSTANT(TRANS_BACK);
526
BIND_ENUM_CONSTANT(TRANS_SPRING);
527
528
BIND_ENUM_CONSTANT(EASE_IN);
529
BIND_ENUM_CONSTANT(EASE_OUT);
530
BIND_ENUM_CONSTANT(EASE_IN_OUT);
531
BIND_ENUM_CONSTANT(EASE_OUT_IN);
532
}
533
534
Tween::Tween() {
535
ERR_FAIL_MSG("Tween can't be created directly. Use create_tween() method.");
536
}
537
538
Tween::Tween(SceneTree *p_parent_tree) {
539
parent_tree = p_parent_tree;
540
valid = true;
541
}
542
543
double PropertyTweener::_get_custom_interpolated_value(const Variant &p_value) {
544
const Variant *argptr = &p_value;
545
546
Variant result;
547
Callable::CallError ce;
548
custom_method.callp(&argptr, 1, result, ce);
549
if (ce.error != Callable::CallError::CALL_OK) {
550
ERR_FAIL_V_MSG(false, "Error calling custom method from PropertyTweener: " + Variant::get_callable_error_text(custom_method, &argptr, 1, ce) + ".");
551
} else if (result.get_type() != Variant::FLOAT) {
552
ERR_FAIL_V_MSG(false, vformat("Wrong return type in PropertyTweener custom method. Expected float, got %s.", Variant::get_type_name(result.get_type())));
553
}
554
return result;
555
}
556
557
RequiredResult<PropertyTweener> PropertyTweener::from(const Variant &p_value) {
558
Ref<Tween> tween = _get_tween();
559
ERR_FAIL_COND_V(tween.is_null(), nullptr);
560
561
Variant from_value = p_value;
562
if (!Animation::validate_type_match(final_val, from_value)) {
563
return nullptr;
564
}
565
566
initial_val = from_value;
567
do_continue = false;
568
return this;
569
}
570
571
RequiredResult<PropertyTweener> PropertyTweener::from_current() {
572
do_continue = false;
573
return this;
574
}
575
576
RequiredResult<PropertyTweener> PropertyTweener::as_relative() {
577
relative = true;
578
return this;
579
}
580
581
RequiredResult<PropertyTweener> PropertyTweener::set_trans(Tween::TransitionType p_trans) {
582
trans_type = p_trans;
583
return this;
584
}
585
586
RequiredResult<PropertyTweener> PropertyTweener::set_ease(Tween::EaseType p_ease) {
587
ease_type = p_ease;
588
return this;
589
}
590
591
RequiredResult<PropertyTweener> PropertyTweener::set_custom_interpolator(const Callable &p_method) {
592
custom_method = p_method;
593
return this;
594
}
595
596
RequiredResult<PropertyTweener> PropertyTweener::set_delay(double p_delay) {
597
delay = p_delay;
598
return this;
599
}
600
601
void PropertyTweener::start() {
602
Tweener::start();
603
604
Object *target_instance = ObjectDB::get_instance(target);
605
if (!target_instance) {
606
return;
607
}
608
609
if (do_continue) {
610
if (Math::is_zero_approx(delay)) {
611
initial_val = target_instance->get_indexed(property);
612
} else {
613
do_continue_delayed = true;
614
}
615
}
616
617
if (relative) {
618
final_val = Animation::add_variant(initial_val, base_final_val);
619
}
620
621
delta_val = Animation::subtract_variant(final_val, initial_val);
622
}
623
624
bool PropertyTweener::step(double &r_delta) {
625
if (finished) {
626
// This is needed in case there's a parallel Tweener with longer duration.
627
return false;
628
}
629
630
Object *target_instance = ObjectDB::get_instance(target);
631
if (!target_instance) {
632
_finish();
633
return false;
634
}
635
elapsed_time += r_delta;
636
637
if (elapsed_time < delay) {
638
r_delta = 0;
639
return true;
640
} else if (do_continue_delayed && !Math::is_zero_approx(delay)) {
641
initial_val = target_instance->get_indexed(property);
642
delta_val = Animation::subtract_variant(final_val, initial_val);
643
do_continue_delayed = false;
644
}
645
646
Ref<Tween> tween = _get_tween();
647
648
double time = MIN(elapsed_time - delay, duration);
649
if (time < duration) {
650
if (custom_method.is_valid()) {
651
const Variant t = tween->interpolate_variant(0.0, 1.0, time, duration, trans_type, ease_type);
652
double result = _get_custom_interpolated_value(t);
653
target_instance->set_indexed(property, Animation::interpolate_variant(initial_val, final_val, result));
654
} else {
655
target_instance->set_indexed(property, tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type));
656
}
657
r_delta = 0;
658
return true;
659
} else {
660
if (custom_method.is_valid()) {
661
double final_t = _get_custom_interpolated_value(1.0);
662
target_instance->set_indexed(property, Animation::interpolate_variant(initial_val, final_val, final_t));
663
} else {
664
target_instance->set_indexed(property, final_val);
665
}
666
r_delta = elapsed_time - delay - duration;
667
_finish();
668
return false;
669
}
670
}
671
672
void PropertyTweener::set_tween(const Ref<Tween> &p_tween) {
673
Tweener::set_tween(p_tween);
674
if (trans_type == Tween::TRANS_MAX) {
675
trans_type = p_tween->get_trans();
676
}
677
if (ease_type == Tween::EASE_MAX) {
678
ease_type = p_tween->get_ease();
679
}
680
}
681
682
void PropertyTweener::_bind_methods() {
683
ClassDB::bind_method(D_METHOD("from", "value"), &PropertyTweener::from);
684
ClassDB::bind_method(D_METHOD("from_current"), &PropertyTweener::from_current);
685
ClassDB::bind_method(D_METHOD("as_relative"), &PropertyTweener::as_relative);
686
ClassDB::bind_method(D_METHOD("set_trans", "trans"), &PropertyTweener::set_trans);
687
ClassDB::bind_method(D_METHOD("set_ease", "ease"), &PropertyTweener::set_ease);
688
ClassDB::bind_method(D_METHOD("set_custom_interpolator", "interpolator_method"), &PropertyTweener::set_custom_interpolator);
689
ClassDB::bind_method(D_METHOD("set_delay", "delay"), &PropertyTweener::set_delay);
690
}
691
692
PropertyTweener::PropertyTweener(const Object *p_target, const Vector<StringName> &p_property, const Variant &p_to, double p_duration) {
693
target = p_target->get_instance_id();
694
property = p_property;
695
initial_val = p_target->get_indexed(property);
696
base_final_val = p_to;
697
final_val = base_final_val;
698
duration = p_duration;
699
700
if (p_target->is_ref_counted()) {
701
ref_copy = p_target;
702
}
703
}
704
705
PropertyTweener::PropertyTweener() {
706
ERR_FAIL_MSG("PropertyTweener can't be created directly. Use the tween_property() method in Tween.");
707
}
708
709
bool IntervalTweener::step(double &r_delta) {
710
if (finished) {
711
return false;
712
}
713
714
elapsed_time += r_delta;
715
716
if (elapsed_time < duration) {
717
r_delta = 0;
718
return true;
719
} else {
720
r_delta = elapsed_time - duration;
721
_finish();
722
return false;
723
}
724
}
725
726
IntervalTweener::IntervalTweener(double p_time) {
727
duration = p_time;
728
}
729
730
IntervalTweener::IntervalTweener() {
731
ERR_FAIL_MSG("IntervalTweener can't be created directly. Use the tween_interval() method in Tween.");
732
}
733
734
RequiredResult<CallbackTweener> CallbackTweener::set_delay(double p_delay) {
735
delay = p_delay;
736
return this;
737
}
738
739
bool CallbackTweener::step(double &r_delta) {
740
if (finished) {
741
return false;
742
}
743
744
if (!callback.is_valid()) {
745
_finish();
746
return false;
747
}
748
749
elapsed_time += r_delta;
750
if (elapsed_time >= delay) {
751
Variant result;
752
Callable::CallError ce;
753
callback.callp(nullptr, 0, result, ce);
754
if (ce.error != Callable::CallError::CALL_OK) {
755
ERR_FAIL_V_MSG(false, "Error calling method from CallbackTweener: " + Variant::get_callable_error_text(callback, nullptr, 0, ce) + ".");
756
}
757
758
r_delta = elapsed_time - delay;
759
_finish();
760
return false;
761
}
762
763
r_delta = 0;
764
return true;
765
}
766
767
void CallbackTweener::_bind_methods() {
768
ClassDB::bind_method(D_METHOD("set_delay", "delay"), &CallbackTweener::set_delay);
769
}
770
771
CallbackTweener::CallbackTweener(const Callable &p_callback) {
772
callback = p_callback;
773
774
Object *callback_instance = p_callback.get_object();
775
if (callback_instance && callback_instance->is_ref_counted()) {
776
ref_copy = callback_instance;
777
}
778
}
779
780
CallbackTweener::CallbackTweener() {
781
ERR_FAIL_MSG("CallbackTweener can't be created directly. Use the tween_callback() method in Tween.");
782
}
783
784
RequiredResult<MethodTweener> MethodTweener::set_delay(double p_delay) {
785
delay = p_delay;
786
return this;
787
}
788
789
RequiredResult<MethodTweener> MethodTweener::set_trans(Tween::TransitionType p_trans) {
790
trans_type = p_trans;
791
return this;
792
}
793
794
RequiredResult<MethodTweener> MethodTweener::set_ease(Tween::EaseType p_ease) {
795
ease_type = p_ease;
796
return this;
797
}
798
799
bool MethodTweener::step(double &r_delta) {
800
if (finished) {
801
return false;
802
}
803
804
if (!callback.is_valid()) {
805
_finish();
806
return false;
807
}
808
809
elapsed_time += r_delta;
810
811
if (elapsed_time < delay) {
812
r_delta = 0;
813
return true;
814
}
815
816
Ref<Tween> tween = _get_tween();
817
818
Variant current_val;
819
double time = MIN(elapsed_time - delay, duration);
820
if (time < duration) {
821
current_val = tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type);
822
} else {
823
current_val = final_val;
824
}
825
const Variant **argptr = (const Variant **)alloca(sizeof(Variant *));
826
argptr[0] = &current_val;
827
828
Variant result;
829
Callable::CallError ce;
830
callback.callp(argptr, 1, result, ce);
831
if (ce.error != Callable::CallError::CALL_OK) {
832
ERR_FAIL_V_MSG(false, "Error calling method from MethodTweener: " + Variant::get_callable_error_text(callback, argptr, 1, ce) + ".");
833
}
834
835
if (time < duration) {
836
r_delta = 0;
837
return true;
838
} else {
839
r_delta = elapsed_time - delay - duration;
840
_finish();
841
return false;
842
}
843
}
844
845
void MethodTweener::set_tween(const Ref<Tween> &p_tween) {
846
Tweener::set_tween(p_tween);
847
if (trans_type == Tween::TRANS_MAX) {
848
trans_type = p_tween->get_trans();
849
}
850
if (ease_type == Tween::EASE_MAX) {
851
ease_type = p_tween->get_ease();
852
}
853
}
854
855
void MethodTweener::_bind_methods() {
856
ClassDB::bind_method(D_METHOD("set_delay", "delay"), &MethodTweener::set_delay);
857
ClassDB::bind_method(D_METHOD("set_trans", "trans"), &MethodTweener::set_trans);
858
ClassDB::bind_method(D_METHOD("set_ease", "ease"), &MethodTweener::set_ease);
859
}
860
861
MethodTweener::MethodTweener(const Callable &p_callback, const Variant &p_from, const Variant &p_to, double p_duration) {
862
callback = p_callback;
863
initial_val = p_from;
864
delta_val = Animation::subtract_variant(p_to, p_from);
865
final_val = p_to;
866
duration = p_duration;
867
868
Object *callback_instance = p_callback.get_object();
869
if (callback_instance && callback_instance->is_ref_counted()) {
870
ref_copy = callback_instance;
871
}
872
}
873
874
MethodTweener::MethodTweener() {
875
ERR_FAIL_MSG("MethodTweener can't be created directly. Use the tween_method() method in Tween.");
876
}
877
878
void SubtweenTweener::start() {
879
Tweener::start();
880
881
// Reset the subtween.
882
subtween->stop();
883
884
// It's possible that a subtween could be killed before it is started;
885
// if so, we just want to skip it entirely.
886
if (subtween->is_valid()) {
887
subtween->play();
888
} else {
889
_finish();
890
}
891
}
892
893
bool SubtweenTweener::step(double &r_delta) {
894
if (finished) {
895
return false;
896
}
897
898
elapsed_time += r_delta;
899
900
if (elapsed_time < delay) {
901
r_delta = 0;
902
return true;
903
}
904
905
if (!subtween->step(r_delta)) {
906
r_delta = elapsed_time - delay - subtween->get_total_time();
907
_finish();
908
return false;
909
}
910
911
r_delta = 0;
912
return true;
913
}
914
915
RequiredResult<SubtweenTweener> SubtweenTweener::set_delay(double p_delay) {
916
delay = p_delay;
917
return this;
918
}
919
920
void SubtweenTweener::_bind_methods() {
921
ClassDB::bind_method(D_METHOD("set_delay", "delay"), &SubtweenTweener::set_delay);
922
}
923
924
SubtweenTweener::SubtweenTweener(const Ref<Tween> &p_subtween) {
925
subtween = p_subtween;
926
}
927
928
SubtweenTweener::SubtweenTweener() {
929
ERR_FAIL_MSG("SubtweenTweener can't be created directly. Use the tween_subtween() method in Tween.");
930
}
931
932