123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789 |
- /**************************************************************************/
- /* tween.cpp */
- /**************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* https://godotengine.org */
- /**************************************************************************/
- /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
- /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
- /* */
- /* Permission is hereby granted, free of charge, to any person obtaining */
- /* a copy of this software and associated documentation files (the */
- /* "Software"), to deal in the Software without restriction, including */
- /* without limitation the rights to use, copy, modify, merge, publish, */
- /* distribute, sublicense, and/or sell copies of the Software, and to */
- /* permit persons to whom the Software is furnished to do so, subject to */
- /* the following conditions: */
- /* */
- /* The above copyright notice and this permission notice shall be */
- /* included in all copies or substantial portions of the Software. */
- /* */
- /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
- /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
- /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
- /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
- /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
- /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
- /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- /**************************************************************************/
- #include "tween.h"
- #include "scene/animation/easing_equations.h"
- #include "scene/main/node.h"
- #include "scene/resources/animation.h"
- Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
- { &linear::in, &linear::in, &linear::in, &linear::in }, // Linear is the same for each easing.
- { &sine::in, &sine::out, &sine::in_out, &sine::out_in },
- { &quint::in, &quint::out, &quint::in_out, &quint::out_in },
- { &quart::in, &quart::out, &quart::in_out, &quart::out_in },
- { &quad::in, &quad::out, &quad::in_out, &quad::out_in },
- { &expo::in, &expo::out, &expo::in_out, &expo::out_in },
- { &elastic::in, &elastic::out, &elastic::in_out, &elastic::out_in },
- { &cubic::in, &cubic::out, &cubic::in_out, &cubic::out_in },
- { &circ::in, &circ::out, &circ::in_out, &circ::out_in },
- { &bounce::in, &bounce::out, &bounce::in_out, &bounce::out_in },
- { &back::in, &back::out, &back::in_out, &back::out_in },
- };
- void Tweener::set_tween(Ref<Tween> p_tween) {
- tween = p_tween;
- }
- void Tweener::clear_tween() {
- tween.unref();
- }
- void Tweener::_bind_methods() {
- ADD_SIGNAL(MethodInfo("finished"));
- }
- bool Tween::_validate_type_match(const Variant &p_from, Variant &r_to) {
- if (p_from.get_type() != r_to.get_type()) {
- // Cast r_to between double and int to avoid minor annoyances.
- if (p_from.get_type() == Variant::FLOAT && r_to.get_type() == Variant::INT) {
- r_to = double(r_to);
- } else if (p_from.get_type() == Variant::INT && r_to.get_type() == Variant::FLOAT) {
- r_to = int(r_to);
- } else {
- ERR_FAIL_V_MSG(false, "Type mismatch between initial and final value: " + Variant::get_type_name(p_from.get_type()) + " and " + Variant::get_type_name(r_to.get_type()));
- }
- }
- return true;
- }
- void Tween::_start_tweeners() {
- if (tweeners.is_empty()) {
- dead = true;
- ERR_FAIL_MSG("Tween without commands, aborting.");
- }
- for (Ref<Tweener> &tweener : tweeners.write[current_step]) {
- tweener->start();
- }
- }
- void Tween::_stop_internal(bool p_reset) {
- running = false;
- if (p_reset) {
- started = false;
- dead = false;
- total_time = 0;
- }
- }
- Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property, Variant p_to, double p_duration) {
- ERR_FAIL_NULL_V(p_target, nullptr);
- ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
- ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
- if (!_validate_type_match(p_target->get_indexed(p_property.get_as_property_path().get_subnames()), p_to)) {
- return nullptr;
- }
- Ref<PropertyTweener> tweener = memnew(PropertyTweener(p_target, p_property, p_to, p_duration));
- append(tweener);
- return tweener;
- }
- Ref<IntervalTweener> Tween::tween_interval(double p_time) {
- ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
- ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
- Ref<IntervalTweener> tweener = memnew(IntervalTweener(p_time));
- append(tweener);
- return tweener;
- }
- Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) {
- ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
- ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
- Ref<CallbackTweener> tweener = memnew(CallbackTweener(p_callback));
- append(tweener);
- return tweener;
- }
- Ref<MethodTweener> Tween::tween_method(Callable p_callback, Variant p_from, Variant p_to, double p_duration) {
- ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
- ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
- if (!_validate_type_match(p_from, p_to)) {
- return nullptr;
- }
- Ref<MethodTweener> tweener = memnew(MethodTweener(p_callback, p_from, p_to, p_duration));
- append(tweener);
- return tweener;
- }
- void Tween::append(Ref<Tweener> p_tweener) {
- p_tweener->set_tween(this);
- if (parallel_enabled) {
- current_step = MAX(current_step, 0);
- } else {
- current_step++;
- }
- parallel_enabled = default_parallel;
- tweeners.resize(current_step + 1);
- tweeners.write[current_step].push_back(p_tweener);
- }
- void Tween::stop() {
- _stop_internal(true);
- }
- void Tween::pause() {
- _stop_internal(false);
- }
- void Tween::play() {
- ERR_FAIL_COND_MSG(!valid, "Tween invalid. Either finished or created outside scene tree.");
- ERR_FAIL_COND_MSG(dead, "Can't play finished Tween, use stop() first to reset its state.");
- running = true;
- }
- void Tween::kill() {
- running = false; // For the sake of is_running().
- dead = true;
- }
- bool Tween::is_running() {
- return running;
- }
- bool Tween::is_valid() {
- return valid;
- }
- void Tween::clear() {
- valid = false;
- for (List<Ref<Tweener>> &step : tweeners) {
- for (Ref<Tweener> &tweener : step) {
- tweener->clear_tween();
- }
- }
- tweeners.clear();
- }
- Ref<Tween> Tween::bind_node(Node *p_node) {
- ERR_FAIL_NULL_V(p_node, this);
- bound_node = p_node->get_instance_id();
- is_bound = true;
- return this;
- }
- Ref<Tween> Tween::set_process_mode(TweenProcessMode p_mode) {
- process_mode = p_mode;
- return this;
- }
- Tween::TweenProcessMode Tween::get_process_mode() {
- return process_mode;
- }
- Ref<Tween> Tween::set_pause_mode(TweenPauseMode p_mode) {
- pause_mode = p_mode;
- return this;
- }
- Tween::TweenPauseMode Tween::get_pause_mode() {
- return pause_mode;
- }
- Ref<Tween> Tween::set_parallel(bool p_parallel) {
- default_parallel = p_parallel;
- parallel_enabled = p_parallel;
- return this;
- }
- Ref<Tween> Tween::set_loops(int p_loops) {
- loops = p_loops;
- return this;
- }
- Ref<Tween> Tween::set_speed_scale(float p_speed) {
- speed_scale = p_speed;
- return this;
- }
- Ref<Tween> Tween::set_trans(TransitionType p_trans) {
- default_transition = p_trans;
- return this;
- }
- Tween::TransitionType Tween::get_trans() {
- return default_transition;
- }
- Ref<Tween> Tween::set_ease(EaseType p_ease) {
- default_ease = p_ease;
- return this;
- }
- Tween::EaseType Tween::get_ease() {
- return default_ease;
- }
- Ref<Tween> Tween::parallel() {
- parallel_enabled = true;
- return this;
- }
- Ref<Tween> Tween::chain() {
- parallel_enabled = false;
- return this;
- }
- bool Tween::custom_step(double p_delta) {
- bool r = running;
- running = true;
- bool ret = step(p_delta);
- running = running && r; // Running might turn false when Tween finished.
- return ret;
- }
- bool Tween::step(double p_delta) {
- if (dead) {
- return false;
- }
- if (!running) {
- return true;
- }
- if (is_bound) {
- Node *node = get_bound_node();
- if (node) {
- if (!node->is_inside_tree()) {
- return true;
- }
- } else {
- return false;
- }
- }
- if (!started) {
- if (tweeners.is_empty()) {
- String tween_id;
- Node *node = get_bound_node();
- if (node) {
- tween_id = vformat("Tween (bound to %s)", node->is_inside_tree() ? (String)node->get_path() : (String)node->get_name());
- } else {
- tween_id = to_string();
- }
- ERR_FAIL_V_MSG(false, tween_id + ": started with no Tweeners.");
- }
- current_step = 0;
- loops_done = 0;
- total_time = 0;
- _start_tweeners();
- started = true;
- }
- double rem_delta = p_delta * speed_scale;
- bool step_active = false;
- total_time += rem_delta;
- #ifdef DEBUG_ENABLED
- double initial_delta = rem_delta;
- bool potential_infinite = false;
- #endif
- while (rem_delta > 0 && running) {
- double step_delta = rem_delta;
- step_active = false;
- for (Ref<Tweener> &tweener : tweeners.write[current_step]) {
- // Modified inside Tweener.step().
- double temp_delta = rem_delta;
- // Turns to true if any Tweener returns true (i.e. is still not finished).
- step_active = tweener->step(temp_delta) || step_active;
- step_delta = MIN(temp_delta, step_delta);
- }
- rem_delta = step_delta;
- if (!step_active) {
- emit_signal(SNAME("step_finished"), current_step);
- current_step++;
- if (current_step == tweeners.size()) {
- loops_done++;
- if (loops_done == loops) {
- running = false;
- dead = true;
- emit_signal(SNAME("finished"));
- break;
- } else {
- emit_signal(SNAME("loop_finished"), loops_done);
- current_step = 0;
- _start_tweeners();
- #ifdef DEBUG_ENABLED
- if (loops <= 0 && Math::is_equal_approx(rem_delta, initial_delta)) {
- if (!potential_infinite) {
- potential_infinite = true;
- } else {
- // Looped twice without using any time, this is 100% certain infinite loop.
- ERR_FAIL_V_MSG(false, "Infinite loop detected. Check set_loops() description for more info.");
- }
- }
- #endif
- }
- } else {
- _start_tweeners();
- }
- }
- }
- return true;
- }
- bool Tween::can_process(bool p_tree_paused) const {
- if (is_bound && pause_mode == TWEEN_PAUSE_BOUND) {
- Node *node = get_bound_node();
- if (node) {
- return node->is_inside_tree() && node->can_process();
- }
- }
- return !p_tree_paused || pause_mode == TWEEN_PAUSE_PROCESS;
- }
- Node *Tween::get_bound_node() const {
- if (is_bound) {
- return Object::cast_to<Node>(ObjectDB::get_instance(bound_node));
- } else {
- return nullptr;
- }
- }
- double Tween::get_total_time() const {
- return total_time;
- }
- 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) {
- if (p_duration == 0) {
- // Special case to avoid dividing by 0 in equations.
- return p_initial + p_delta;
- }
- interpolater func = interpolaters[p_trans_type][p_ease_type];
- return func(p_time, p_initial, p_delta, p_duration);
- }
- Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, double p_time, double p_duration, TransitionType p_trans, EaseType p_ease) {
- ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant());
- ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant());
- // Special case for bool.
- if (p_initial_val.get_type() == Variant::BOOL) {
- return run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration) >= 0.5;
- }
- Variant ret = Animation::add_variant(p_initial_val, p_delta_val);
- ret = Animation::interpolate_variant(p_initial_val, ret, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
- return ret;
- }
- String Tween::to_string() {
- String ret = Object::to_string();
- Node *node = get_bound_node();
- if (node) {
- ret += vformat(" (bound to %s)", node->get_name());
- }
- return ret;
- }
- void Tween::_bind_methods() {
- ClassDB::bind_method(D_METHOD("tween_property", "object", "property", "final_val", "duration"), &Tween::tween_property);
- ClassDB::bind_method(D_METHOD("tween_interval", "time"), &Tween::tween_interval);
- ClassDB::bind_method(D_METHOD("tween_callback", "callback"), &Tween::tween_callback);
- ClassDB::bind_method(D_METHOD("tween_method", "method", "from", "to", "duration"), &Tween::tween_method);
- ClassDB::bind_method(D_METHOD("custom_step", "delta"), &Tween::custom_step);
- ClassDB::bind_method(D_METHOD("stop"), &Tween::stop);
- ClassDB::bind_method(D_METHOD("pause"), &Tween::pause);
- ClassDB::bind_method(D_METHOD("play"), &Tween::play);
- ClassDB::bind_method(D_METHOD("kill"), &Tween::kill);
- ClassDB::bind_method(D_METHOD("get_total_elapsed_time"), &Tween::get_total_time);
- ClassDB::bind_method(D_METHOD("is_running"), &Tween::is_running);
- ClassDB::bind_method(D_METHOD("is_valid"), &Tween::is_valid);
- ClassDB::bind_method(D_METHOD("bind_node", "node"), &Tween::bind_node);
- ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Tween::set_process_mode);
- ClassDB::bind_method(D_METHOD("set_pause_mode", "mode"), &Tween::set_pause_mode);
- ClassDB::bind_method(D_METHOD("set_parallel", "parallel"), &Tween::set_parallel, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("set_loops", "loops"), &Tween::set_loops, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("set_speed_scale", "speed"), &Tween::set_speed_scale);
- ClassDB::bind_method(D_METHOD("set_trans", "trans"), &Tween::set_trans);
- ClassDB::bind_method(D_METHOD("set_ease", "ease"), &Tween::set_ease);
- ClassDB::bind_method(D_METHOD("parallel"), &Tween::parallel);
- ClassDB::bind_method(D_METHOD("chain"), &Tween::chain);
- ClassDB::bind_static_method("Tween", D_METHOD("interpolate_value", "initial_value", "delta_value", "elapsed_time", "duration", "trans_type", "ease_type"), &Tween::interpolate_variant);
- ADD_SIGNAL(MethodInfo("step_finished", PropertyInfo(Variant::INT, "idx")));
- ADD_SIGNAL(MethodInfo("loop_finished", PropertyInfo(Variant::INT, "loop_count")));
- ADD_SIGNAL(MethodInfo("finished"));
- BIND_ENUM_CONSTANT(TWEEN_PROCESS_PHYSICS);
- BIND_ENUM_CONSTANT(TWEEN_PROCESS_IDLE);
- BIND_ENUM_CONSTANT(TWEEN_PAUSE_BOUND);
- BIND_ENUM_CONSTANT(TWEEN_PAUSE_STOP);
- BIND_ENUM_CONSTANT(TWEEN_PAUSE_PROCESS);
- BIND_ENUM_CONSTANT(TRANS_LINEAR);
- BIND_ENUM_CONSTANT(TRANS_SINE);
- BIND_ENUM_CONSTANT(TRANS_QUINT);
- BIND_ENUM_CONSTANT(TRANS_QUART);
- BIND_ENUM_CONSTANT(TRANS_QUAD);
- BIND_ENUM_CONSTANT(TRANS_EXPO);
- BIND_ENUM_CONSTANT(TRANS_ELASTIC);
- BIND_ENUM_CONSTANT(TRANS_CUBIC);
- BIND_ENUM_CONSTANT(TRANS_CIRC);
- BIND_ENUM_CONSTANT(TRANS_BOUNCE);
- BIND_ENUM_CONSTANT(TRANS_BACK);
- BIND_ENUM_CONSTANT(EASE_IN);
- BIND_ENUM_CONSTANT(EASE_OUT);
- BIND_ENUM_CONSTANT(EASE_IN_OUT);
- BIND_ENUM_CONSTANT(EASE_OUT_IN);
- }
- Tween::Tween() {
- ERR_FAIL_MSG("Tween can't be created directly. Use create_tween() method.");
- }
- Tween::Tween(bool p_valid) {
- valid = p_valid;
- }
- Ref<PropertyTweener> PropertyTweener::from(Variant p_value) {
- ERR_FAIL_COND_V(tween.is_null(), nullptr);
- if (!tween->_validate_type_match(p_value, final_val)) {
- return nullptr;
- }
- initial_val = p_value;
- do_continue = false;
- return this;
- }
- Ref<PropertyTweener> PropertyTweener::from_current() {
- do_continue = false;
- return this;
- }
- Ref<PropertyTweener> PropertyTweener::as_relative() {
- relative = true;
- return this;
- }
- Ref<PropertyTweener> PropertyTweener::set_trans(Tween::TransitionType p_trans) {
- trans_type = p_trans;
- return this;
- }
- Ref<PropertyTweener> PropertyTweener::set_ease(Tween::EaseType p_ease) {
- ease_type = p_ease;
- return this;
- }
- Ref<PropertyTweener> PropertyTweener::set_delay(double p_delay) {
- delay = p_delay;
- return this;
- }
- void PropertyTweener::start() {
- elapsed_time = 0;
- finished = false;
- Object *target_instance = ObjectDB::get_instance(target);
- if (!target_instance) {
- WARN_PRINT("Target object freed before starting, aborting Tweener.");
- return;
- }
- if (do_continue) {
- initial_val = target_instance->get_indexed(property);
- }
- if (relative) {
- final_val = Animation::add_variant(initial_val, base_final_val);
- }
- delta_val = Animation::subtract_variant(final_val, initial_val);
- }
- bool PropertyTweener::step(double &r_delta) {
- if (finished) {
- // This is needed in case there's a parallel Tweener with longer duration.
- return false;
- }
- Object *target_instance = ObjectDB::get_instance(target);
- if (!target_instance) {
- return false;
- }
- elapsed_time += r_delta;
- if (elapsed_time < delay) {
- r_delta = 0;
- return true;
- }
- double time = MIN(elapsed_time - delay, duration);
- if (time < duration) {
- target_instance->set_indexed(property, tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type));
- r_delta = 0;
- return true;
- } else {
- target_instance->set_indexed(property, final_val);
- finished = true;
- r_delta = elapsed_time - delay - duration;
- emit_signal(SNAME("finished"));
- return false;
- }
- }
- void PropertyTweener::set_tween(Ref<Tween> p_tween) {
- tween = p_tween;
- if (trans_type == Tween::TRANS_MAX) {
- trans_type = tween->get_trans();
- }
- if (ease_type == Tween::EASE_MAX) {
- ease_type = tween->get_ease();
- }
- }
- void PropertyTweener::_bind_methods() {
- ClassDB::bind_method(D_METHOD("from", "value"), &PropertyTweener::from);
- ClassDB::bind_method(D_METHOD("from_current"), &PropertyTweener::from_current);
- ClassDB::bind_method(D_METHOD("as_relative"), &PropertyTweener::as_relative);
- ClassDB::bind_method(D_METHOD("set_trans", "trans"), &PropertyTweener::set_trans);
- ClassDB::bind_method(D_METHOD("set_ease", "ease"), &PropertyTweener::set_ease);
- ClassDB::bind_method(D_METHOD("set_delay", "delay"), &PropertyTweener::set_delay);
- }
- PropertyTweener::PropertyTweener(Object *p_target, NodePath p_property, Variant p_to, double p_duration) {
- target = p_target->get_instance_id();
- property = p_property.get_as_property_path().get_subnames();
- initial_val = p_target->get_indexed(property);
- base_final_val = p_to;
- final_val = base_final_val;
- duration = p_duration;
- if (p_target->is_ref_counted()) {
- ref_copy = p_target;
- }
- }
- PropertyTweener::PropertyTweener() {
- ERR_FAIL_MSG("PropertyTweener can't be created directly. Use the tween_property() method in Tween.");
- }
- void IntervalTweener::start() {
- elapsed_time = 0;
- finished = false;
- }
- bool IntervalTweener::step(double &r_delta) {
- if (finished) {
- return false;
- }
- elapsed_time += r_delta;
- if (elapsed_time < duration) {
- r_delta = 0;
- return true;
- } else {
- finished = true;
- r_delta = elapsed_time - duration;
- emit_signal(SNAME("finished"));
- return false;
- }
- }
- IntervalTweener::IntervalTweener(double p_time) {
- duration = p_time;
- }
- IntervalTweener::IntervalTweener() {
- ERR_FAIL_MSG("IntervalTweener can't be created directly. Use the tween_interval() method in Tween.");
- }
- Ref<CallbackTweener> CallbackTweener::set_delay(double p_delay) {
- delay = p_delay;
- return this;
- }
- void CallbackTweener::start() {
- elapsed_time = 0;
- finished = false;
- }
- bool CallbackTweener::step(double &r_delta) {
- if (finished) {
- return false;
- }
- elapsed_time += r_delta;
- if (elapsed_time >= delay) {
- Variant result;
- Callable::CallError ce;
- callback.callp(nullptr, 0, result, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_FAIL_V_MSG(false, "Error calling method from CallbackTweener: " + Variant::get_callable_error_text(callback, nullptr, 0, ce));
- }
- finished = true;
- r_delta = elapsed_time - delay;
- emit_signal(SNAME("finished"));
- return false;
- }
- r_delta = 0;
- return true;
- }
- void CallbackTweener::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_delay", "delay"), &CallbackTweener::set_delay);
- }
- CallbackTweener::CallbackTweener(Callable p_callback) {
- callback = p_callback;
- Object *callback_instance = p_callback.get_object();
- if (callback_instance && callback_instance->is_ref_counted()) {
- ref_copy = callback_instance;
- }
- }
- CallbackTweener::CallbackTweener() {
- ERR_FAIL_MSG("CallbackTweener can't be created directly. Use the tween_callback() method in Tween.");
- }
- Ref<MethodTweener> MethodTweener::set_delay(double p_delay) {
- delay = p_delay;
- return this;
- }
- Ref<MethodTweener> MethodTweener::set_trans(Tween::TransitionType p_trans) {
- trans_type = p_trans;
- return this;
- }
- Ref<MethodTweener> MethodTweener::set_ease(Tween::EaseType p_ease) {
- ease_type = p_ease;
- return this;
- }
- void MethodTweener::start() {
- elapsed_time = 0;
- finished = false;
- }
- bool MethodTweener::step(double &r_delta) {
- if (finished) {
- return false;
- }
- elapsed_time += r_delta;
- if (elapsed_time < delay) {
- r_delta = 0;
- return true;
- }
- Variant current_val;
- double time = MIN(elapsed_time - delay, duration);
- if (time < duration) {
- current_val = tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type);
- } else {
- current_val = final_val;
- }
- const Variant **argptr = (const Variant **)alloca(sizeof(Variant *));
- argptr[0] = ¤t_val;
- Variant result;
- Callable::CallError ce;
- callback.callp(argptr, 1, result, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_FAIL_V_MSG(false, "Error calling method from MethodTweener: " + Variant::get_callable_error_text(callback, argptr, 1, ce));
- }
- if (time < duration) {
- r_delta = 0;
- return true;
- } else {
- finished = true;
- r_delta = elapsed_time - delay - duration;
- emit_signal(SNAME("finished"));
- return false;
- }
- }
- void MethodTweener::set_tween(Ref<Tween> p_tween) {
- tween = p_tween;
- if (trans_type == Tween::TRANS_MAX) {
- trans_type = tween->get_trans();
- }
- if (ease_type == Tween::EASE_MAX) {
- ease_type = tween->get_ease();
- }
- }
- void MethodTweener::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_delay", "delay"), &MethodTweener::set_delay);
- ClassDB::bind_method(D_METHOD("set_trans", "trans"), &MethodTweener::set_trans);
- ClassDB::bind_method(D_METHOD("set_ease", "ease"), &MethodTweener::set_ease);
- }
- MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, double p_duration) {
- callback = p_callback;
- initial_val = p_from;
- delta_val = Animation::subtract_variant(p_to, p_from);
- final_val = p_to;
- duration = p_duration;
- Object *callback_instance = p_callback.get_object();
- if (callback_instance && callback_instance->is_ref_counted()) {
- ref_copy = callback_instance;
- }
- }
- MethodTweener::MethodTweener() {
- ERR_FAIL_MSG("MethodTweener can't be created directly. Use the tween_method() method in Tween.");
- }
|