2014-08-20 06:01:41 +02:00
/**************************************************************************/
/* 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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-08-20 06:01:41 +02:00
# include "tween.h"
2018-09-11 18:13:45 +02:00
2021-09-24 13:23:49 +02:00
# include "scene/animation/easing_equations.h"
2020-09-05 03:05:30 +02:00
# include "scene/main/node.h"
2022-09-06 05:24:06 +02:00
# include "scene/resources/animation.h"
2019-06-09 05:11:42 +02:00
2023-02-12 22:19:40 +01:00
# define CHECK_VALID() \
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. " ) ;
2021-09-24 13:23:49 +02:00
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 } ,
2023-05-10 07:03:36 +02:00
{ & spring : : in , & spring : : out , & spring : : in_out , & spring : : out_in } ,
2021-09-24 13:23:49 +02:00
} ;
2023-02-12 22:19:40 +01:00
void Tweener : : set_tween ( const Ref < Tween > & p_tween ) {
2024-02-26 10:29:37 +01:00
tween_id = p_tween - > get_instance_id ( ) ;
2020-09-05 03:05:30 +02:00
}
2024-02-26 10:29:37 +01:00
Ref < Tween > Tweener : : _get_tween ( ) {
return Ref < Tween > ( ObjectDB : : get_instance ( tween_id ) ) ;
2021-08-05 13:05:14 +02:00
}
2020-09-05 03:05:30 +02:00
void Tweener : : _bind_methods ( ) {
ADD_SIGNAL ( MethodInfo ( " finished " ) ) ;
}
2023-02-12 22:08:25 +01:00
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 ;
}
2023-01-11 14:08:14 +01:00
void Tween : : _start_tweeners ( ) {
2020-09-05 03:05:30 +02:00
if ( tweeners . is_empty ( ) ) {
dead = true ;
ERR_FAIL_MSG ( " Tween without commands, aborting. " ) ;
2020-05-14 16:41:43 +02:00
}
2020-09-05 03:05:30 +02:00
2021-07-26 17:50:35 +02:00
for ( Ref < Tweener > & tweener : tweeners . write [ current_step ] ) {
tweener - > start ( ) ;
2020-05-14 16:41:43 +02:00
}
2015-05-05 05:12:17 +02:00
}
2023-01-11 14:08:14 +01:00
void Tween : : _stop_internal ( bool p_reset ) {
running = false ;
if ( p_reset ) {
started = false ;
dead = false ;
total_time = 0 ;
}
}
2023-02-12 22:19:40 +01:00
Ref < PropertyTweener > Tween : : tween_property ( const Object * p_target , const NodePath & p_property , Variant p_to , double p_duration ) {
2020-09-05 03:05:30 +02:00
ERR_FAIL_NULL_V ( p_target , nullptr ) ;
2023-02-12 22:19:40 +01:00
CHECK_VALID ( ) ;
2019-06-09 05:11:42 +02:00
2023-02-12 22:19:40 +01:00
Vector < StringName > property_subnames = p_property . get_as_property_path ( ) . get_subnames ( ) ;
2023-09-10 22:18:34 +02:00
# ifdef DEBUG_ENABLED
bool prop_valid ;
const Variant & prop_value = p_target - > get_indexed ( property_subnames , & prop_valid ) ;
ERR_FAIL_COND_V_MSG ( ! prop_valid , nullptr , vformat ( " The tweened property \" %s \" does not exist in object \" %s \" . " , p_property , p_target ) ) ;
# else
const Variant & prop_value = p_target - > get_indexed ( property_subnames ) ;
# endif
if ( ! _validate_type_match ( prop_value , p_to ) ) {
2023-02-12 22:08:25 +01:00
return nullptr ;
2022-08-30 10:43:32 +02:00
}
2021-09-16 01:15:31 +02:00
2023-02-12 22:19:40 +01:00
Ref < PropertyTweener > tweener = memnew ( PropertyTweener ( p_target , property_subnames , p_to , p_duration ) ) ;
2020-09-05 03:05:30 +02:00
append ( tweener ) ;
return tweener ;
2015-05-05 05:12:17 +02:00
}
2022-09-22 15:54:15 +02:00
Ref < IntervalTweener > Tween : : tween_interval ( double p_time ) {
2023-02-12 22:19:40 +01:00
CHECK_VALID ( ) ;
2014-08-20 06:01:41 +02:00
2020-09-05 03:05:30 +02:00
Ref < IntervalTweener > tweener = memnew ( IntervalTweener ( p_time ) ) ;
append ( tweener ) ;
return tweener ;
}
2014-08-20 10:39:28 +02:00
2023-02-12 22:19:40 +01:00
Ref < CallbackTweener > Tween : : tween_callback ( const Callable & p_callback ) {
CHECK_VALID ( ) ;
2020-09-05 03:05:30 +02:00
Ref < CallbackTweener > tweener = memnew ( CallbackTweener ( p_callback ) ) ;
append ( tweener ) ;
return tweener ;
2014-08-20 06:01:41 +02:00
}
2023-02-12 22:19:40 +01:00
Ref < MethodTweener > Tween : : tween_method ( const Callable & p_callback , const Variant p_from , Variant p_to , double p_duration ) {
CHECK_VALID ( ) ;
2014-08-20 06:01:41 +02:00
2023-02-12 22:08:25 +01:00
if ( ! _validate_type_match ( p_from , p_to ) ) {
return nullptr ;
}
2020-09-05 03:05:30 +02:00
Ref < MethodTweener > tweener = memnew ( MethodTweener ( p_callback , p_from , p_to , p_duration ) ) ;
append ( tweener ) ;
return tweener ;
}
2014-08-20 10:39:28 +02:00
2021-08-05 13:05:14 +02:00
void Tween : : append ( Ref < Tweener > p_tweener ) {
2020-09-05 03:05:30 +02:00
p_tweener - > set_tween ( this ) ;
if ( parallel_enabled ) {
current_step = MAX ( current_step , 0 ) ;
} else {
current_step + + ;
2014-08-20 06:01:41 +02:00
}
2020-09-05 03:05:30 +02:00
parallel_enabled = default_parallel ;
2014-08-20 06:01:41 +02:00
2020-09-05 03:05:30 +02:00
tweeners . resize ( current_step + 1 ) ;
tweeners . write [ current_step ] . push_back ( p_tweener ) ;
}
2014-08-20 06:01:41 +02:00
2020-09-05 03:05:30 +02:00
void Tween : : stop ( ) {
2023-01-11 14:08:14 +01:00
_stop_internal ( true ) ;
2020-09-05 03:05:30 +02:00
}
2016-03-09 00:00:52 +01:00
2020-09-05 03:05:30 +02:00
void Tween : : pause ( ) {
2023-01-11 14:08:14 +01:00
_stop_internal ( false ) ;
2020-09-05 03:05:30 +02:00
}
2014-08-20 06:01:41 +02:00
2020-09-05 03:05:30 +02:00
void Tween : : play ( ) {
2021-08-05 13:05:14 +02:00
ERR_FAIL_COND_MSG ( ! valid , " Tween invalid. Either finished or created outside scene tree. " ) ;
2020-09-05 03:05:30 +02:00
ERR_FAIL_COND_MSG ( dead , " Can't play finished Tween, use stop() first to reset its state. " ) ;
running = true ;
}
2016-03-09 00:00:52 +01:00
2020-09-05 03:05:30 +02:00
void Tween : : kill ( ) {
running = false ; // For the sake of is_running().
dead = true ;
2014-08-20 06:01:41 +02:00
}
2020-09-05 03:05:30 +02:00
bool Tween : : is_running ( ) {
return running ;
}
2017-03-05 16:44:50 +01:00
2020-09-05 03:05:30 +02:00
bool Tween : : is_valid ( ) {
2021-08-05 13:05:14 +02:00
return valid ;
}
void Tween : : clear ( ) {
valid = false ;
tweeners . clear ( ) ;
2020-09-05 03:05:30 +02:00
}
2017-08-20 17:45:01 +02:00
2023-02-12 22:19:40 +01:00
Ref < Tween > Tween : : bind_node ( const Node * p_node ) {
2021-08-02 14:15:40 +02:00
ERR_FAIL_NULL_V ( p_node , this ) ;
2020-09-05 03:05:30 +02:00
bound_node = p_node - > get_instance_id ( ) ;
is_bound = true ;
return this ;
}
2017-08-20 17:45:01 +02:00
2020-09-05 03:05:30 +02:00
Ref < Tween > Tween : : set_process_mode ( TweenProcessMode p_mode ) {
process_mode = p_mode ;
return this ;
2014-08-20 06:01:41 +02:00
}
2020-09-05 03:05:30 +02:00
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 ;
}
2023-03-21 04:49:31 +01:00
int Tween : : get_loops_left ( ) const {
if ( loops < = 0 ) {
return - 1 ; // Infinite loop.
} else {
return loops - loops_done ;
}
}
2020-09-05 03:05:30 +02:00
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 ;
}
2018-09-26 13:13:56 +02:00
2020-09-05 03:05:30 +02:00
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 ;
}
2022-09-22 15:54:15 +02:00
bool Tween : : custom_step ( double p_delta ) {
2020-09-05 03:05:30 +02:00
bool r = running ;
running = true ;
bool ret = step ( p_delta ) ;
running = running & & r ; // Running might turn false when Tween finished.
return ret ;
}
2022-09-22 15:54:15 +02:00
bool Tween : : step ( double p_delta ) {
2020-09-05 03:05:30 +02:00
if ( dead ) {
return false ;
2014-08-25 07:36:56 +02:00
}
2019-10-23 22:38:43 +02:00
2020-09-05 03:05:30 +02:00
if ( is_bound ) {
2022-09-29 11:53:28 +02:00
Node * node = get_bound_node ( ) ;
if ( node ) {
if ( ! node - > is_inside_tree ( ) ) {
2020-09-05 03:05:30 +02:00
return true ;
}
} else {
return false ;
2019-10-23 22:38:43 +02:00
}
}
2023-07-25 13:29:30 +02:00
if ( ! running ) {
return true ;
}
2020-09-05 03:05:30 +02:00
if ( ! started ) {
2022-12-13 22:37:41 +01:00
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. " ) ;
}
2020-09-05 03:05:30 +02:00
current_step = 0 ;
loops_done = 0 ;
2022-03-22 17:39:01 +01:00
total_time = 0 ;
2023-01-11 14:08:14 +01:00
_start_tweeners ( ) ;
2020-09-05 03:05:30 +02:00
started = true ;
}
2017-03-05 16:44:50 +01:00
2022-09-22 15:54:15 +02:00
double rem_delta = p_delta * speed_scale ;
2020-09-05 03:05:30 +02:00
bool step_active = false ;
2022-03-22 17:39:01 +01:00
total_time + = rem_delta ;
2019-06-09 05:11:42 +02:00
2022-04-30 23:19:20 +02:00
# ifdef DEBUG_ENABLED
2022-09-22 15:54:15 +02:00
double initial_delta = rem_delta ;
2022-04-30 23:19:20 +02:00
bool potential_infinite = false ;
# endif
2020-09-05 03:05:30 +02:00
while ( rem_delta > 0 & & running ) {
2022-09-22 15:54:15 +02:00
double step_delta = rem_delta ;
2020-09-05 03:05:30 +02:00
step_active = false ;
2021-07-26 17:50:35 +02:00
for ( Ref < Tweener > & tweener : tweeners . write [ current_step ] ) {
2020-09-05 03:05:30 +02:00
// Modified inside Tweener.step().
2022-09-22 15:54:15 +02:00
double temp_delta = rem_delta ;
2020-09-05 03:05:30 +02:00
// Turns to true if any Tweener returns true (i.e. is still not finished).
2021-07-26 17:50:35 +02:00
step_active = tweener - > step ( temp_delta ) | | step_active ;
2021-10-28 21:04:22 +02:00
step_delta = MIN ( temp_delta , step_delta ) ;
2018-09-26 13:13:56 +02:00
}
2014-08-25 07:36:56 +02:00
2020-09-05 03:05:30 +02:00
rem_delta = step_delta ;
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
if ( ! step_active ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " step_finished " ) , current_step ) ;
2020-09-05 03:05:30 +02:00
current_step + + ;
2014-08-25 07:36:56 +02:00
2020-09-05 03:05:30 +02:00
if ( current_step = = tweeners . size ( ) ) {
loops_done + + ;
if ( loops_done = = loops ) {
running = false ;
dead = true ;
2024-05-13 16:56:03 +02:00
emit_signal ( SceneStringName ( finished ) ) ;
2022-09-16 14:20:12 +02:00
break ;
2020-09-05 03:05:30 +02:00
} else {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " loop_finished " ) , loops_done ) ;
2020-09-05 03:05:30 +02:00
current_step = 0 ;
2023-01-11 14:08:14 +01:00
_start_tweeners ( ) ;
2022-04-30 23:19:20 +02:00
# 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
2020-09-05 03:05:30 +02:00
}
} else {
2023-01-11 14:08:14 +01:00
_start_tweeners ( ) ;
2020-09-05 03:05:30 +02:00
}
2018-09-26 13:13:56 +02:00
}
2020-09-05 03:05:30 +02:00
}
return true ;
}
2018-09-26 13:13:56 +02:00
2022-01-09 18:23:53 +01:00
bool Tween : : can_process ( bool p_tree_paused ) const {
2020-09-05 03:05:30 +02:00
if ( is_bound & & pause_mode = = TWEEN_PAUSE_BOUND ) {
2022-09-29 11:53:28 +02:00
Node * node = get_bound_node ( ) ;
if ( node ) {
return node - > is_inside_tree ( ) & & node - > can_process ( ) ;
2020-09-05 03:05:30 +02:00
}
2014-08-25 07:36:56 +02:00
}
2020-09-05 03:05:30 +02:00
2022-01-09 18:23:53 +01:00
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 ;
}
2014-08-25 07:36:56 +02:00
}
2022-09-22 15:54:15 +02:00
double Tween : : get_total_time ( ) const {
2022-03-22 17:39:01 +01:00
return total_time ;
}
2021-09-24 13:23:49 +02:00
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 ) ;
}
2023-02-12 22:19:40 +01:00
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 ) {
2020-09-05 03:05:30 +02:00
ERR_FAIL_INDEX_V ( p_trans , TransitionType : : TRANS_MAX , Variant ( ) ) ;
ERR_FAIL_INDEX_V ( p_ease , EaseType : : EASE_MAX , Variant ( ) ) ;
2014-08-20 06:01:41 +02:00
2022-09-06 05:24:06 +02:00
Variant ret = Animation : : add_variant ( p_initial_val , p_delta_val ) ;
2023-11-10 13:29:45 +01:00
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 ( ) ) ;
2022-09-06 05:24:06 +02:00
return ret ;
2014-08-20 06:01:41 +02:00
}
2022-12-13 22:37:41 +01:00
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 ;
}
2020-09-05 03:05:30 +02:00
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 ) ;
2022-03-22 17:39:01 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_total_elapsed_time " ) , & Tween : : get_total_time ) ;
2020-09-05 03:05:30 +02:00
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 ) ) ;
2023-03-21 04:49:31 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_loops_left " ) , & Tween : : get_loops_left ) ;
2020-09-05 03:05:30 +02:00
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 ) ;
2014-08-20 06:01:41 +02:00
2020-09-05 03:05:30 +02:00
ClassDB : : bind_method ( D_METHOD ( " parallel " ) , & Tween : : parallel ) ;
ClassDB : : bind_method ( D_METHOD ( " chain " ) , & Tween : : chain ) ;
2019-06-09 05:11:42 +02:00
2022-04-17 23:13:39 +02:00
ClassDB : : bind_static_method ( " Tween " , D_METHOD ( " interpolate_value " , " initial_value " , " delta_value " , " elapsed_time " , " duration " , " trans_type " , " ease_type " ) , & Tween : : interpolate_variant ) ;
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
ADD_SIGNAL ( MethodInfo ( " step_finished " , PropertyInfo ( Variant : : INT , " idx " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " loop_finished " , PropertyInfo ( Variant : : INT , " loop_count " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " finished " ) ) ;
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
BIND_ENUM_CONSTANT ( TWEEN_PROCESS_PHYSICS ) ;
BIND_ENUM_CONSTANT ( TWEEN_PROCESS_IDLE ) ;
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
BIND_ENUM_CONSTANT ( TWEEN_PAUSE_BOUND ) ;
BIND_ENUM_CONSTANT ( TWEEN_PAUSE_STOP ) ;
BIND_ENUM_CONSTANT ( TWEEN_PAUSE_PROCESS ) ;
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
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 ) ;
2023-05-10 07:03:36 +02:00
BIND_ENUM_CONSTANT ( TRANS_SPRING ) ;
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
BIND_ENUM_CONSTANT ( EASE_IN ) ;
BIND_ENUM_CONSTANT ( EASE_OUT ) ;
BIND_ENUM_CONSTANT ( EASE_IN_OUT ) ;
BIND_ENUM_CONSTANT ( EASE_OUT_IN ) ;
}
2014-08-20 06:01:41 +02:00
2022-04-17 23:13:39 +02:00
Tween : : Tween ( ) {
ERR_FAIL_MSG ( " Tween can't be created directly. Use create_tween() method. " ) ;
}
Tween : : Tween ( bool p_valid ) {
valid = p_valid ;
}
2023-02-12 22:19:40 +01:00
Ref < PropertyTweener > PropertyTweener : : from ( const Variant & p_value ) {
2024-02-26 10:29:37 +01:00
Ref < Tween > tween = _get_tween ( ) ;
2023-02-28 14:24:51 +01:00
ERR_FAIL_COND_V ( tween . is_null ( ) , nullptr ) ;
2024-01-22 03:47:52 +01:00
Variant from_value = p_value ;
if ( ! tween - > _validate_type_match ( final_val , from_value ) ) {
2023-02-28 14:24:51 +01:00
return nullptr ;
}
2024-01-22 03:47:52 +01:00
initial_val = from_value ;
2020-09-05 03:05:30 +02:00
do_continue = false ;
return this ;
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
Ref < PropertyTweener > PropertyTweener : : from_current ( ) {
do_continue = false ;
return this ;
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
Ref < PropertyTweener > PropertyTweener : : as_relative ( ) {
relative = true ;
return this ;
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
Ref < PropertyTweener > PropertyTweener : : set_trans ( Tween : : TransitionType p_trans ) {
trans_type = p_trans ;
return this ;
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
Ref < PropertyTweener > PropertyTweener : : set_ease ( Tween : : EaseType p_ease ) {
ease_type = p_ease ;
return this ;
}
2014-08-20 06:01:41 +02:00
2023-09-25 15:56:04 +02:00
Ref < PropertyTweener > PropertyTweener : : set_custom_interpolator ( const Callable & p_method ) {
custom_method = p_method ;
return this ;
}
2022-09-22 15:54:15 +02:00
Ref < PropertyTweener > PropertyTweener : : set_delay ( double p_delay ) {
2020-09-05 03:05:30 +02:00
delay = p_delay ;
return this ;
2014-08-20 06:01:41 +02:00
}
2020-09-05 03:05:30 +02:00
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. " ) ;
2020-03-06 08:40:40 +01:00
return ;
2015-05-05 05:12:17 +02:00
}
2014-08-20 06:01:41 +02:00
2023-12-02 20:20:50 +01:00
if ( do_continue ) {
if ( Math : : is_zero_approx ( delay ) ) {
initial_val = target_instance - > get_indexed ( property ) ;
} else {
do_continue_delayed = true ;
}
2020-05-14 16:41:43 +02:00
}
2014-08-20 06:01:41 +02:00
2020-09-05 03:05:30 +02:00
if ( relative ) {
2022-09-06 05:24:06 +02:00
final_val = Animation : : add_variant ( initial_val , base_final_val ) ;
2020-05-14 16:41:43 +02:00
}
2014-08-20 06:01:41 +02:00
2022-09-06 05:24:06 +02:00
delta_val = Animation : : subtract_variant ( final_val , initial_val ) ;
2019-06-09 05:11:42 +02:00
}
2014-08-20 06:01:41 +02:00
2022-09-22 15:54:15 +02:00
bool PropertyTweener : : step ( double & r_delta ) {
2020-09-05 03:05:30 +02:00
if ( finished ) {
// This is needed in case there's a parallel Tweener with longer duration.
return false ;
2019-06-09 05:11:42 +02:00
}
2014-08-20 06:01:41 +02:00
2020-09-05 03:05:30 +02:00
Object * target_instance = ObjectDB : : get_instance ( target ) ;
if ( ! target_instance ) {
return false ;
2020-05-14 16:41:43 +02:00
}
2020-09-05 03:05:30 +02:00
elapsed_time + = r_delta ;
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
if ( elapsed_time < delay ) {
r_delta = 0 ;
return true ;
2023-12-02 20:20:50 +01:00
} else if ( do_continue_delayed & & ! Math : : is_zero_approx ( delay ) ) {
2023-08-17 10:28:26 +02:00
initial_val = target_instance - > get_indexed ( property ) ;
delta_val = Animation : : subtract_variant ( final_val , initial_val ) ;
2023-12-02 20:20:50 +01:00
do_continue_delayed = false ;
2015-05-05 05:12:17 +02:00
}
2016-04-07 09:45:16 +02:00
2024-02-26 10:29:37 +01:00
Ref < Tween > tween = _get_tween ( ) ;
2022-09-22 15:54:15 +02:00
double time = MIN ( elapsed_time - delay , duration ) ;
2020-09-05 03:05:30 +02:00
if ( time < duration ) {
2023-09-25 15:56:04 +02:00
if ( custom_method . is_valid ( ) ) {
const Variant t = tween - > interpolate_variant ( 0.0 , 1.0 , time , duration , trans_type , ease_type ) ;
const Variant * argptr = & t ;
Variant result ;
Callable : : CallError ce ;
custom_method . callp ( & argptr , 1 , result , ce ) ;
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
ERR_FAIL_V_MSG ( false , " Error calling custom method from PropertyTweener: " + Variant : : get_callable_error_text ( custom_method , & argptr , 1 , ce ) + " . " ) ;
} else if ( result . get_type ( ) ! = Variant : : FLOAT ) {
ERR_FAIL_V_MSG ( false , vformat ( " Wrong return type in PropertyTweener custom method. Expected float, got %s. " , Variant : : get_type_name ( result . get_type ( ) ) ) ) ;
}
target_instance - > set_indexed ( property , Animation : : interpolate_variant ( initial_val , final_val , result ) ) ;
} else {
target_instance - > set_indexed ( property , tween - > interpolate_variant ( initial_val , delta_val , time , duration , trans_type , ease_type ) ) ;
}
2020-09-05 03:05:30 +02:00
r_delta = 0 ;
return true ;
2020-05-14 16:41:43 +02:00
} else {
2022-03-27 03:09:12 +02:00
target_instance - > set_indexed ( property , final_val ) ;
2020-09-05 03:05:30 +02:00
finished = true ;
r_delta = elapsed_time - delay - duration ;
2024-05-13 16:56:03 +02:00
emit_signal ( SceneStringName ( finished ) ) ;
2020-09-05 03:05:30 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2015-01-07 12:46:01 +01:00
}
2023-02-12 22:19:40 +01:00
void PropertyTweener : : set_tween ( const Ref < Tween > & p_tween ) {
2024-02-26 10:29:37 +01:00
Tweener : : set_tween ( p_tween ) ;
2020-09-05 03:05:30 +02:00
if ( trans_type = = Tween : : TRANS_MAX ) {
2024-02-26 10:29:37 +01:00
trans_type = p_tween - > get_trans ( ) ;
2015-05-05 05:12:17 +02:00
}
2020-09-05 03:05:30 +02:00
if ( ease_type = = Tween : : EASE_MAX ) {
2024-02-26 10:29:37 +01:00
ease_type = p_tween - > get_ease ( ) ;
2020-05-14 16:41:43 +02:00
}
2020-09-05 03:05:30 +02:00
}
2015-01-07 12:46:01 +01:00
2020-09-05 03:05:30 +02:00
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 ) ;
2023-09-25 15:56:04 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_interpolator " , " interpolator_method " ) , & PropertyTweener : : set_custom_interpolator ) ;
2020-09-05 03:05:30 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_delay " , " delay " ) , & PropertyTweener : : set_delay ) ;
}
2014-08-25 07:36:56 +02:00
2023-02-12 22:19:40 +01:00
PropertyTweener : : PropertyTweener ( const Object * p_target , const Vector < StringName > & p_property , const Variant & p_to , double p_duration ) {
2020-09-05 03:05:30 +02:00
target = p_target - > get_instance_id ( ) ;
2023-02-12 22:19:40 +01:00
property = p_property ;
2020-09-05 03:05:30 +02:00
initial_val = p_target - > get_indexed ( property ) ;
base_final_val = p_to ;
final_val = base_final_val ;
duration = p_duration ;
2023-01-01 11:27:53 +01:00
if ( p_target - > is_ref_counted ( ) ) {
ref_copy = p_target ;
}
2014-08-25 07:36:56 +02:00
}
2020-09-05 03:05:30 +02:00
PropertyTweener : : PropertyTweener ( ) {
2023-01-30 15:56:14 +01:00
ERR_FAIL_MSG ( " PropertyTweener can't be created directly. Use the tween_property() method in Tween. " ) ;
2020-09-05 03:05:30 +02:00
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
void IntervalTweener : : start ( ) {
elapsed_time = 0 ;
finished = false ;
}
2017-05-30 22:20:15 +02:00
2022-09-22 15:54:15 +02:00
bool IntervalTweener : : step ( double & r_delta ) {
2020-09-05 03:05:30 +02:00
if ( finished ) {
return false ;
2020-05-14 16:41:43 +02:00
}
2017-05-30 22:21:50 +02:00
2020-09-05 03:05:30 +02:00
elapsed_time + = r_delta ;
if ( elapsed_time < duration ) {
r_delta = 0 ;
return true ;
} else {
finished = true ;
r_delta = elapsed_time - duration ;
2024-05-13 16:56:03 +02:00
emit_signal ( SceneStringName ( finished ) ) ;
2020-09-05 03:05:30 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2020-09-05 03:05:30 +02:00
}
2014-08-25 07:36:56 +02:00
2022-09-22 15:54:15 +02:00
IntervalTweener : : IntervalTweener ( double p_time ) {
2020-09-05 03:05:30 +02:00
duration = p_time ;
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
IntervalTweener : : IntervalTweener ( ) {
2023-01-30 15:56:14 +01:00
ERR_FAIL_MSG ( " IntervalTweener can't be created directly. Use the tween_interval() method in Tween. " ) ;
2020-09-05 03:05:30 +02:00
}
2019-06-09 05:11:42 +02:00
2022-09-22 15:54:15 +02:00
Ref < CallbackTweener > CallbackTweener : : set_delay ( double p_delay ) {
2020-09-05 03:05:30 +02:00
delay = p_delay ;
return this ;
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
void CallbackTweener : : start ( ) {
elapsed_time = 0 ;
finished = false ;
}
2014-08-25 07:36:56 +02:00
2022-09-22 15:54:15 +02:00
bool CallbackTweener : : step ( double & r_delta ) {
2020-09-05 03:05:30 +02:00
if ( finished ) {
return false ;
}
2014-08-25 07:36:56 +02:00
2023-09-26 21:58:57 +02:00
if ( ! callback . is_valid ( ) ) {
2023-08-29 14:45:36 +02:00
return false ;
}
2020-09-05 03:05:30 +02:00
elapsed_time + = r_delta ;
if ( elapsed_time > = delay ) {
Variant result ;
Callable : : CallError ce ;
2022-07-28 22:56:41 +02:00
callback . callp ( nullptr , 0 , result , ce ) ;
2020-09-05 03:05:30 +02:00
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
2023-09-25 15:56:04 +02:00
ERR_FAIL_V_MSG ( false , " Error calling method from CallbackTweener: " + Variant : : get_callable_error_text ( callback , nullptr , 0 , ce ) + " . " ) ;
2020-09-05 03:05:30 +02:00
}
2014-08-25 07:36:56 +02:00
2020-09-05 03:05:30 +02:00
finished = true ;
r_delta = elapsed_time - delay ;
2024-05-13 16:56:03 +02:00
emit_signal ( SceneStringName ( finished ) ) ;
2020-09-05 03:05:30 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
r_delta = 0 ;
return true ;
}
2014-08-25 07:36:56 +02:00
2020-09-05 03:05:30 +02:00
void CallbackTweener : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " set_delay " , " delay " ) , & CallbackTweener : : set_delay ) ;
}
2019-06-09 05:11:42 +02:00
2023-02-12 22:19:40 +01:00
CallbackTweener : : CallbackTweener ( const Callable & p_callback ) {
2020-09-05 03:05:30 +02:00
callback = p_callback ;
2023-01-01 11:27:53 +01:00
Object * callback_instance = p_callback . get_object ( ) ;
if ( callback_instance & & callback_instance - > is_ref_counted ( ) ) {
ref_copy = callback_instance ;
}
2020-09-05 03:05:30 +02:00
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
CallbackTweener : : CallbackTweener ( ) {
2023-01-30 15:56:14 +01:00
ERR_FAIL_MSG ( " CallbackTweener can't be created directly. Use the tween_callback() method in Tween. " ) ;
2020-09-05 03:05:30 +02:00
}
2019-06-09 05:11:42 +02:00
2022-09-22 15:54:15 +02:00
Ref < MethodTweener > MethodTweener : : set_delay ( double p_delay ) {
2020-09-05 03:05:30 +02:00
delay = p_delay ;
return this ;
}
2014-08-25 07:36:56 +02:00
2020-09-05 03:05:30 +02:00
Ref < MethodTweener > MethodTweener : : set_trans ( Tween : : TransitionType p_trans ) {
trans_type = p_trans ;
return this ;
}
2014-08-25 07:36:56 +02:00
2020-09-05 03:05:30 +02:00
Ref < MethodTweener > MethodTweener : : set_ease ( Tween : : EaseType p_ease ) {
ease_type = p_ease ;
return this ;
}
2014-08-25 07:36:56 +02:00
2020-09-05 03:05:30 +02:00
void MethodTweener : : start ( ) {
elapsed_time = 0 ;
finished = false ;
}
2017-05-30 22:20:15 +02:00
2022-09-22 15:54:15 +02:00
bool MethodTweener : : step ( double & r_delta ) {
2020-09-05 03:05:30 +02:00
if ( finished ) {
return false ;
2020-05-14 16:41:43 +02:00
}
2014-08-25 07:36:56 +02:00
2023-09-26 21:58:57 +02:00
if ( ! callback . is_valid ( ) ) {
2023-08-29 14:45:36 +02:00
return false ;
}
2020-09-05 03:05:30 +02:00
elapsed_time + = r_delta ;
2014-08-25 07:36:56 +02:00
2020-09-05 03:05:30 +02:00
if ( elapsed_time < delay ) {
r_delta = 0 ;
return true ;
2020-03-06 08:40:40 +01:00
}
2014-08-22 05:24:53 +02:00
2024-02-26 10:29:37 +01:00
Ref < Tween > tween = _get_tween ( ) ;
2022-03-27 03:09:12 +02:00
Variant current_val ;
2022-09-22 15:54:15 +02:00
double time = MIN ( elapsed_time - delay , duration ) ;
2022-03-27 03:09:12 +02:00
if ( time < duration ) {
current_val = tween - > interpolate_variant ( initial_val , delta_val , time , duration , trans_type , ease_type ) ;
} else {
current_val = final_val ;
}
2020-09-05 03:05:30 +02:00
const Variant * * argptr = ( const Variant * * ) alloca ( sizeof ( Variant * ) ) ;
argptr [ 0 ] = & current_val ;
2014-08-22 05:24:53 +02:00
2020-09-05 03:05:30 +02:00
Variant result ;
Callable : : CallError ce ;
2022-07-28 22:56:41 +02:00
callback . callp ( argptr , 1 , result , ce ) ;
2020-09-05 03:05:30 +02:00
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
2023-09-25 15:56:04 +02:00
ERR_FAIL_V_MSG ( false , " Error calling method from MethodTweener: " + Variant : : get_callable_error_text ( callback , argptr , 1 , ce ) + " . " ) ;
2015-05-05 05:12:17 +02:00
}
2019-06-09 05:11:42 +02:00
2020-09-05 03:05:30 +02:00
if ( time < duration ) {
r_delta = 0 ;
return true ;
} else {
finished = true ;
r_delta = elapsed_time - delay - duration ;
2024-05-13 16:56:03 +02:00
emit_signal ( SceneStringName ( finished ) ) ;
2020-09-05 03:05:30 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2020-09-05 03:05:30 +02:00
}
2014-08-25 07:36:56 +02:00
2023-02-12 22:19:40 +01:00
void MethodTweener : : set_tween ( const Ref < Tween > & p_tween ) {
2024-02-26 10:29:37 +01:00
Tweener : : set_tween ( p_tween ) ;
2020-09-05 03:05:30 +02:00
if ( trans_type = = Tween : : TRANS_MAX ) {
2024-02-26 10:29:37 +01:00
trans_type = p_tween - > get_trans ( ) ;
2020-05-14 16:41:43 +02:00
}
2020-09-05 03:05:30 +02:00
if ( ease_type = = Tween : : EASE_MAX ) {
2024-02-26 10:29:37 +01:00
ease_type = p_tween - > get_ease ( ) ;
2020-03-06 08:40:40 +01:00
}
2020-09-05 03:05:30 +02:00
}
2014-08-25 07:36:56 +02:00
2020-09-05 03:05:30 +02:00
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 ) ;
2014-08-25 07:36:56 +02:00
}
2023-02-12 22:19:40 +01:00
MethodTweener : : MethodTweener ( const Callable & p_callback , const Variant & p_from , const Variant & p_to , double p_duration ) {
2020-09-05 03:05:30 +02:00
callback = p_callback ;
initial_val = p_from ;
2022-09-06 05:24:06 +02:00
delta_val = Animation : : subtract_variant ( p_to , p_from ) ;
2022-03-27 03:09:12 +02:00
final_val = p_to ;
2020-09-05 03:05:30 +02:00
duration = p_duration ;
2023-01-01 11:27:53 +01:00
Object * callback_instance = p_callback . get_object ( ) ;
if ( callback_instance & & callback_instance - > is_ref_counted ( ) ) {
ref_copy = callback_instance ;
}
2014-08-20 06:01:41 +02:00
}
2020-09-05 03:05:30 +02:00
MethodTweener : : MethodTweener ( ) {
2023-01-30 15:56:14 +01:00
ERR_FAIL_MSG ( " MethodTweener can't be created directly. Use the tween_method() method in Tween. " ) ;
2014-08-20 06:01:41 +02:00
}