2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* animation_player.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-02-10 02:10:30 +01:00
# include "animation_player.h"
2023-07-20 17:34:06 +02:00
# include "animation_player.compat.inc"
2016-03-09 00:00:52 +01:00
2020-11-07 23:33:38 +01:00
# include "core/config/engine.h"
2017-10-30 19:43:19 +01:00
2017-03-05 16:44:50 +01:00
bool AnimationPlayer : : _set ( const StringName & p_name , const Variant & p_value ) {
String name = p_name ;
2023-07-20 17:34:06 +02:00
if ( name . begins_with ( " playback/play " ) ) { // For backward compatibility.
2018-01-11 23:35:12 +01:00
set_current_animation ( p_value ) ;
2014-02-10 02:10:30 +01:00
} else if ( name . begins_with ( " next/ " ) ) {
2017-03-05 16:44:50 +01:00
String which = name . get_slicec ( ' / ' , 1 ) ;
animation_set_next ( which , p_value ) ;
2023-09-04 17:01:33 +02:00
} else if ( p_name = = SceneStringName ( blend_times ) ) {
2017-03-05 16:44:50 +01:00
Array array = p_value ;
2014-02-10 02:10:30 +01:00
int len = array . size ( ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( len % 3 , false ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < len / 3 ; i + + ) {
StringName from = array [ i * 3 + 0 ] ;
StringName to = array [ i * 3 + 1 ] ;
float time = array [ i * 3 + 2 ] ;
set_blend_time ( from , to , time ) ;
2014-02-10 02:10:30 +01:00
}
2023-07-20 17:34:06 +02:00
# ifndef DISABLE_DEPRECATED
} else if ( p_name = = " method_call_mode " ) {
set_callback_mode_method ( static_cast < AnimationCallbackModeMethod > ( ( int ) p_value ) ) ;
} else if ( p_name = = " playback_process_mode " ) {
set_callback_mode_process ( static_cast < AnimationCallbackModeProcess > ( ( int ) p_value ) ) ;
} else if ( p_name = = " playback_active " ) {
set_active ( p_value ) ;
# endif // DISABLE_DEPRECATED
2020-05-14 16:41:43 +02:00
} else {
2014-02-10 02:10:30 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return true ;
}
2017-03-05 16:44:50 +01:00
bool AnimationPlayer : : _get ( const StringName & p_name , Variant & r_ret ) const {
String name = p_name ;
2014-02-10 02:10:30 +01:00
2023-07-20 17:34:06 +02:00
if ( name = = " playback/play " ) { // For backward compatibility.
2016-03-09 00:00:52 +01:00
2018-01-11 23:35:12 +01:00
r_ret = get_current_animation ( ) ;
2014-02-10 02:10:30 +01:00
} else if ( name . begins_with ( " next/ " ) ) {
2017-03-05 16:44:50 +01:00
String which = name . get_slicec ( ' / ' , 1 ) ;
r_ret = animation_get_next ( which ) ;
2014-02-10 02:10:30 +01:00
2024-05-13 16:56:03 +02:00
} else if ( p_name = = SceneStringName ( blend_times ) ) {
2017-01-16 18:03:38 +01:00
Vector < BlendKey > keys ;
2022-09-22 15:54:15 +02:00
for ( const KeyValue < BlendKey , double > & E : blend_times ) {
2021-08-09 22:13:42 +02:00
keys . ordered_insert ( E . key ) ;
2014-02-10 02:10:30 +01:00
}
2017-01-16 18:03:38 +01:00
Array array ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < keys . size ( ) ; i + + ) {
2017-01-16 18:03:38 +01:00
array . push_back ( keys [ i ] . from ) ;
array . push_back ( keys [ i ] . to ) ;
2022-05-13 15:04:37 +02:00
array . push_back ( blend_times . get ( keys [ i ] ) ) ;
2017-01-16 18:03:38 +01:00
}
2017-03-05 16:44:50 +01:00
r_ret = array ;
2023-07-20 17:34:06 +02:00
# ifndef DISABLE_DEPRECATED
} else if ( name = = " method_call_mode " ) {
r_ret = get_callback_mode_method ( ) ;
} else if ( name = = " playback_process_mode " ) {
r_ret = get_callback_mode_process ( ) ;
} else if ( name = = " playback_active " ) {
r_ret = is_active ( ) ;
# endif // DISABLE_DEPRECATED
2020-05-14 16:41:43 +02:00
} else {
2014-02-10 02:10:30 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
return true ;
}
2022-08-12 22:57:11 +02:00
void AnimationPlayer : : _validate_property ( PropertyInfo & p_property ) const {
2023-07-20 17:34:06 +02:00
AnimationMixer : : _validate_property ( p_property ) ;
2022-08-12 22:57:11 +02:00
if ( p_property . name = = " current_animation " ) {
2018-01-11 23:35:12 +01:00
List < String > names ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < StringName , AnimationData > & E : animation_set ) {
names . push_back ( E . key ) ;
2018-01-11 23:35:12 +01:00
}
names . push_front ( " [stop] " ) ;
String hint ;
for ( List < String > : : Element * E = names . front ( ) ; E ; E = E - > next ( ) ) {
2020-05-14 16:41:43 +02:00
if ( E ! = names . front ( ) ) {
2018-01-11 23:35:12 +01:00
hint + = " , " ;
2020-05-14 16:41:43 +02:00
}
2018-01-11 23:35:12 +01:00
hint + = E - > get ( ) ;
}
2022-08-12 22:57:11 +02:00
p_property . hint_string = hint ;
2024-05-02 22:36:36 +02:00
} else if ( ! auto_capture & & p_property . name . begins_with ( " playback_auto_capture_ " ) ) {
p_property . usage = PROPERTY_USAGE_NONE ;
2018-01-11 23:35:12 +01:00
}
}
void AnimationPlayer : : _get_property_list ( List < PropertyInfo > * p_list ) const {
2016-02-01 04:19:45 +01:00
List < PropertyInfo > anim_names ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < StringName , AnimationData > & E : animation_set ) {
2023-07-20 17:34:06 +02:00
HashMap < StringName , StringName > : : ConstIterator F = animation_next_set . find ( E . key ) ;
if ( F & & F - > value ! = StringName ( ) ) {
2021-11-03 23:06:17 +01:00
anim_names . push_back ( PropertyInfo ( Variant : : STRING , " next/ " + String ( E . key ) , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : anim_names ) {
2021-07-16 05:45:57 +02:00
p_list - > push_back ( E ) ;
2016-02-01 04:19:45 +01:00
}
2014-02-10 02:10:30 +01:00
2021-11-03 23:06:17 +01:00
p_list - > push_back ( PropertyInfo ( Variant : : ARRAY , " blend_times " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
2014-02-10 02:10:30 +01:00
}
void AnimationPlayer : : _notification ( int p_what ) {
2017-03-05 16:44:50 +01:00
switch ( p_what ) {
2014-02-10 02:10:30 +01:00
case NOTIFICATION_READY : {
2017-08-19 01:02:56 +02:00
if ( ! Engine : : get_singleton ( ) - > is_editor_hint ( ) & & animation_set . has ( autoplay ) ) {
2024-04-27 06:05:46 +02:00
set_active ( active ) ;
2014-02-10 02:10:30 +01:00
play ( autoplay ) ;
2023-11-25 22:28:22 +01:00
_check_immediately_after_start ( ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
}
}
2024-07-16 07:38:56 +02:00
void AnimationPlayer : : _process_playback_data ( PlaybackData & cd , double p_delta , float p_blend , bool p_seeked , bool p_internal_seeked , bool p_started , bool p_is_current ) {
2023-07-20 17:34:06 +02:00
double speed = speed_scale * cd . speed_scale ;
bool backwards = signbit ( speed ) ; // Negative zero means playing backwards too.
double delta = p_started ? 0 : p_delta * speed ;
2021-05-21 08:42:37 +02:00
double next_pos = cd . pos + delta ;
2016-03-09 00:00:52 +01:00
2024-08-31 08:57:34 +02:00
double start = get_section_start_time ( ) ;
double end = get_section_end_time ( ) ;
2022-11-29 10:51:45 +01:00
Animation : : LoopedFlag looped_flag = Animation : : LOOPED_FLAG_NONE ;
2021-10-15 15:25:00 +02:00
switch ( cd . from - > animation - > get_loop_mode ( ) ) {
2022-05-04 20:53:48 +02:00
case Animation : : LOOP_NONE : {
2024-08-31 08:57:34 +02:00
if ( Animation : : is_less_approx ( next_pos , start ) ) {
next_pos = start ;
} else if ( Animation : : is_greater_approx ( next_pos , end ) ) {
next_pos = end ;
2021-10-15 15:25:00 +02:00
}
2022-12-07 10:28:36 +01:00
delta = next_pos - cd . pos ; // Fix delta (after determination of backwards because negative zero is lost here).
2021-10-15 15:25:00 +02:00
} break ;
2014-02-10 02:10:30 +01:00
2022-05-04 20:53:48 +02:00
case Animation : : LOOP_LINEAR : {
2024-08-31 08:57:34 +02:00
if ( Animation : : is_less_approx ( next_pos , start ) & & Animation : : is_greater_or_equal_approx ( cd . pos , start ) ) {
2022-11-29 10:51:45 +01:00
looped_flag = Animation : : LOOPED_FLAG_START ;
2014-02-10 02:10:30 +01:00
}
2024-08-31 08:57:34 +02:00
if ( Animation : : is_greater_approx ( next_pos , end ) & & Animation : : is_less_or_equal_approx ( cd . pos , end ) ) {
2022-11-29 10:51:45 +01:00
looped_flag = Animation : : LOOPED_FLAG_END ;
}
2024-08-31 08:57:34 +02:00
next_pos = Math : : fposmod ( next_pos - start , end - start ) + start ;
2021-10-15 15:25:00 +02:00
} break ;
2014-02-10 02:10:30 +01:00
2022-05-04 20:53:48 +02:00
case Animation : : LOOP_PINGPONG : {
2024-08-31 08:57:34 +02:00
if ( Animation : : is_less_approx ( next_pos , start ) & & Animation : : is_greater_or_equal_approx ( cd . pos , start ) ) {
2022-11-29 10:51:45 +01:00
cd . speed_scale * = - 1.0 ;
looped_flag = Animation : : LOOPED_FLAG_START ;
2021-04-24 22:47:03 +02:00
}
2024-08-31 08:57:34 +02:00
if ( Animation : : is_greater_approx ( next_pos , end ) & & Animation : : is_less_or_equal_approx ( cd . pos , end ) ) {
2022-11-29 10:51:45 +01:00
cd . speed_scale * = - 1.0 ;
looped_flag = Animation : : LOOPED_FLAG_END ;
2021-10-15 15:25:00 +02:00
}
2024-08-31 08:57:34 +02:00
next_pos = Math : : pingpong ( next_pos - start , end - start ) + start ;
2021-10-15 15:25:00 +02:00
} break ;
2014-02-10 02:10:30 +01:00
2021-10-15 15:25:00 +02:00
default :
break ;
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2022-12-07 10:28:36 +01:00
double prev_pos = cd . pos ; // The animation may be changed during process, so it is safer that the state is changed before process.
2022-12-07 14:34:41 +01:00
// End detection.
2023-07-20 17:34:06 +02:00
if ( p_is_current ) {
if ( cd . from - > animation - > get_loop_mode ( ) = = Animation : : LOOP_NONE ) {
2024-08-31 08:57:34 +02:00
if ( ! backwards & & Animation : : is_less_or_equal_approx ( prev_pos , end ) & & Math : : is_equal_approx ( next_pos , end ) ) {
2023-07-20 17:34:06 +02:00
// Playback finished.
2024-08-31 08:57:34 +02:00
next_pos = end ; // Snap to the edge.
2023-07-20 17:34:06 +02:00
end_reached = true ;
2024-08-31 08:57:34 +02:00
end_notify = Animation : : is_less_approx ( prev_pos , end ) ; // Notify only if not already at the end.
2023-07-20 17:34:06 +02:00
p_blend = 1.0 ;
2023-01-27 19:25:49 +01:00
}
2024-08-31 08:57:34 +02:00
if ( backwards & & Animation : : is_greater_or_equal_approx ( prev_pos , start ) & & Math : : is_equal_approx ( next_pos , start ) ) {
2023-07-20 17:34:06 +02:00
// Playback finished.
2024-08-31 08:57:34 +02:00
next_pos = start ; // Snap to the edge.
2023-07-20 17:34:06 +02:00
end_reached = true ;
2024-08-31 08:57:34 +02:00
end_notify = Animation : : is_greater_approx ( prev_pos , start ) ; // Notify only if not already at the beginning.
2023-07-20 17:34:06 +02:00
p_blend = 1.0 ;
2023-01-27 19:25:49 +01:00
}
}
}
2014-02-10 02:10:30 +01:00
2024-08-01 16:57:47 +02:00
cd . pos = next_pos ;
2023-07-20 17:34:06 +02:00
PlaybackInfo pi ;
if ( p_started ) {
pi . time = prev_pos ;
pi . delta = 0 ;
2024-08-31 08:57:34 +02:00
pi . start = start ;
pi . end = end ;
2023-07-20 17:34:06 +02:00
pi . seeked = true ;
2014-02-10 02:10:30 +01:00
} else {
2023-07-20 17:34:06 +02:00
pi . time = next_pos ;
pi . delta = delta ;
2024-08-31 08:57:34 +02:00
pi . start = start ;
pi . end = end ;
2023-07-20 17:34:06 +02:00
pi . seeked = p_seeked ;
2022-04-07 13:49:28 +02:00
}
2024-06-07 10:51:19 +02:00
if ( Math : : is_zero_approx ( pi . delta ) & & backwards ) {
pi . delta = - 0.0 ; // Sign is needed to handle converted Continuous track from Discrete track correctly.
}
2024-07-16 07:38:56 +02:00
// Immediately after playback, discrete keys should be retrieved with EXACT mode since behind keys must be ignored at that time.
pi . is_external_seeking = ! p_internal_seeked & & ! p_started ;
2023-07-20 17:34:06 +02:00
pi . looped_flag = looped_flag ;
pi . weight = p_blend ;
make_animation_instance ( cd . from - > name , pi ) ;
2022-04-07 13:49:28 +02:00
}
2023-12-16 01:42:48 +01:00
float AnimationPlayer : : get_current_blend_amount ( ) {
Playback & c = playback ;
float blend = 1.0 ;
for ( List < Blend > : : Element * E = c . blend . front ( ) ; E ; E = E - > next ( ) ) {
Blend & b = E - > get ( ) ;
blend = blend - b . blend_left ;
}
return MAX ( 0 , blend ) ;
}
2023-07-20 17:34:06 +02:00
void AnimationPlayer : : _blend_playback_data ( double p_delta , bool p_started ) {
Playback & c = playback ;
2022-04-07 13:49:28 +02:00
2023-07-20 17:34:06 +02:00
bool seeked = c . seeked ; // The animation may be changed during process, so it is safer that the state is changed before process.
2024-07-16 07:38:56 +02:00
bool internal_seeked = c . internal_seeked ;
2022-04-07 13:49:28 +02:00
2024-06-07 10:51:19 +02:00
if ( ! Math : : is_zero_approx ( p_delta ) ) {
2023-07-20 17:34:06 +02:00
c . seeked = false ;
2024-07-16 07:38:56 +02:00
c . internal_seeked = false ;
2023-07-20 17:34:06 +02:00
}
2022-04-07 13:49:28 +02:00
2023-07-20 17:34:06 +02:00
// Second, process current animation to check if the animation end reached.
2024-07-16 07:38:56 +02:00
_process_playback_data ( c . current , p_delta , get_current_blend_amount ( ) , seeked , internal_seeked , p_started , true ) ;
2022-04-07 13:49:28 +02:00
2023-07-20 17:34:06 +02:00
// Finally, if not end the animation, do blending.
if ( end_reached ) {
playback . blend . clear ( ) ;
return ;
}
List < List < Blend > : : Element * > to_erase ;
for ( List < Blend > : : Element * E = c . blend . front ( ) ; E ; E = E - > next ( ) ) {
Blend & b = E - > get ( ) ;
2023-12-16 01:42:48 +01:00
b . blend_left = MAX ( 0 , b . blend_left - Math : : absf ( speed_scale * p_delta ) / b . blend_time ) ;
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_or_equal_approx ( b . blend_left , 0 ) ) {
2023-07-20 17:34:06 +02:00
to_erase . push_back ( E ) ;
b . blend_left = CMP_EPSILON ; // May want to play last frame.
2022-04-07 13:49:28 +02:00
}
2023-07-20 17:34:06 +02:00
// Note: There may be issues if an animation event triggers an animation change while this blend is active,
// so it is best to use "deferred" calls instead of "immediate" for animation events that can trigger new animations.
2024-07-16 07:38:56 +02:00
_process_playback_data ( b . data , p_delta , b . blend_left , false , false , false ) ;
2022-04-07 13:49:28 +02:00
}
2023-07-20 17:34:06 +02:00
for ( List < Blend > : : Element * & E : to_erase ) {
c . blend . erase ( E ) ;
2022-04-07 13:49:28 +02:00
}
}
2023-07-20 17:34:06 +02:00
bool AnimationPlayer : : _blend_pre_process ( double p_delta , int p_track_count , const HashMap < NodePath , int > & p_track_map ) {
if ( ! playback . current . from ) {
_set_process ( false ) ;
return false ;
2022-04-07 13:49:28 +02:00
}
2023-07-20 17:34:06 +02:00
tmp_from = playback . current . from - > animation - > get_instance_id ( ) ;
end_reached = false ;
end_notify = false ;
2014-02-10 02:10:30 +01:00
2023-07-20 17:34:06 +02:00
bool started = playback . started ; // The animation may be changed during process, so it is safer that the state is changed before process.
if ( playback . started ) {
playback . started = false ;
2014-02-10 02:10:30 +01:00
}
2023-07-20 17:34:06 +02:00
AnimationData * prev_from = playback . current . from ;
_blend_playback_data ( p_delta , started ) ;
2014-02-10 02:10:30 +01:00
2023-07-20 17:34:06 +02:00
if ( prev_from ! = playback . current . from ) {
return false ; // Animation has been changed in the process (may be caused by method track), abort process.
2014-02-10 02:10:30 +01:00
}
2023-07-20 17:34:06 +02:00
return true ;
2014-02-10 02:10:30 +01:00
}
2024-01-05 18:40:58 +01:00
void AnimationPlayer : : _blend_capture ( double p_delta ) {
blend_capture ( p_delta * Math : : abs ( speed_scale ) ) ;
}
2023-07-20 17:34:06 +02:00
void AnimationPlayer : : _blend_post_process ( ) {
if ( end_reached ) {
// If the method track changes current animation, the animation is not finished.
if ( tmp_from = = playback . current . from - > animation - > get_instance_id ( ) ) {
if ( playback_queue . size ( ) ) {
String old = playback . assigned ;
play ( playback_queue . front ( ) - > get ( ) ) ;
String new_name = playback . assigned ;
playback_queue . pop_front ( ) ;
if ( end_notify ) {
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( animation_changed ) , old , new_name ) ;
2023-07-20 17:34:06 +02:00
}
} else {
_clear_caches ( ) ;
playing = false ;
_set_process ( false ) ;
if ( end_notify ) {
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( animation_finished ) , playback . assigned ) ;
2023-07-20 17:34:06 +02:00
if ( movie_quit_on_finish & & OS : : get_singleton ( ) - > has_feature ( " movie " ) ) {
print_line ( vformat ( " Movie Maker mode is enabled. Quitting on animation finish as requested by: %s " , get_path ( ) ) ) ;
get_tree ( ) - > quit ( ) ;
}
}
}
}
end_reached = false ;
end_notify = false ;
2020-05-14 16:41:43 +02:00
}
2023-07-20 17:34:06 +02:00
tmp_from = ObjectID ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : queue ( const StringName & p_name ) {
2020-05-14 16:41:43 +02:00
if ( ! is_playing ( ) ) {
2014-02-10 02:10:30 +01:00
play ( p_name ) ;
2020-05-14 16:41:43 +02:00
} else {
2023-07-20 17:34:06 +02:00
playback_queue . push_back ( p_name ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-02-17 22:06:54 +01:00
Vector < String > AnimationPlayer : : get_queue ( ) {
Vector < String > ret ;
2023-07-20 17:34:06 +02:00
for ( const StringName & E : playback_queue ) {
2021-07-16 05:45:57 +02:00
ret . push_back ( E ) ;
2018-11-28 01:43:34 +01:00
}
return ret ;
}
2014-02-10 02:10:30 +01:00
void AnimationPlayer : : clear_queue ( ) {
2023-07-20 17:34:06 +02:00
playback_queue . clear ( ) ;
2018-06-07 17:46:14 +02:00
}
2014-02-10 02:10:30 +01:00
2022-09-22 15:54:15 +02:00
void AnimationPlayer : : play_backwards ( const StringName & p_name , double p_custom_blend ) {
2017-03-05 16:44:50 +01:00
play ( p_name , p_custom_blend , - 1 , true ) ;
2015-09-10 05:10:54 +02:00
}
2024-08-31 08:57:34 +02:00
void AnimationPlayer : : play_section_with_markers_backwards ( const StringName & p_name , const StringName & p_start_marker , const StringName & p_end_marker , double p_custom_blend ) {
play_section_with_markers ( p_name , p_start_marker , p_end_marker , p_custom_blend , - 1 , true ) ;
}
void AnimationPlayer : : play_section_backwards ( const StringName & p_name , double p_start_time , double p_end_time , double p_custom_blend ) {
play_section ( p_name , p_start_time , p_end_time , - 1 , true ) ;
}
2024-05-02 04:23:11 +02:00
void AnimationPlayer : : play ( const StringName & p_name , double p_custom_blend , float p_custom_scale , bool p_from_end ) {
if ( auto_capture ) {
2024-05-02 22:36:36 +02:00
play_with_capture ( p_name , auto_capture_duration , p_custom_blend , p_custom_scale , p_from_end , auto_capture_transition_type , auto_capture_ease_type ) ;
2024-05-02 04:23:11 +02:00
} else {
_play ( p_name , p_custom_blend , p_custom_scale , p_from_end ) ;
2024-01-05 18:40:58 +01:00
}
}
2024-05-02 04:23:11 +02:00
void AnimationPlayer : : _play ( const StringName & p_name , double p_custom_blend , float p_custom_scale , bool p_from_end ) {
2024-08-31 08:57:34 +02:00
play_section_with_markers ( p_name , StringName ( ) , StringName ( ) , p_custom_blend , p_custom_scale , p_from_end ) ;
}
void AnimationPlayer : : play_section_with_markers ( const StringName & p_name , const StringName & p_start_marker , const StringName & p_end_marker , double p_custom_blend , float p_custom_scale , bool p_from_end ) {
2017-03-05 16:44:50 +01:00
StringName name = p_name ;
2016-03-09 00:00:52 +01:00
2024-01-05 18:40:58 +01:00
if ( name = = StringName ( ) ) {
2017-03-05 16:44:50 +01:00
name = playback . assigned ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-05-14 18:54:14 +02:00
ERR_FAIL_COND_MSG ( ! animation_set . has ( name ) , vformat ( " Animation not found: %s. " , name ) ) ;
2016-03-09 00:00:52 +01:00
2024-08-31 08:57:34 +02:00
Ref < Animation > animation = animation_set [ name ] . animation ;
ERR_FAIL_COND_MSG ( p_start_marker = = p_end_marker & & p_start_marker , vformat ( " Start marker and end marker cannot be the same marker: %s. " , p_start_marker ) ) ;
ERR_FAIL_COND_MSG ( p_start_marker & & ! animation - > has_marker ( p_start_marker ) , vformat ( " Marker %s not found in animation: %s. " , p_start_marker , name ) ) ;
ERR_FAIL_COND_MSG ( p_end_marker & & ! animation - > has_marker ( p_end_marker ) , vformat ( " Marker %s not found in animation: %s. " , p_end_marker , name ) ) ;
double start_time = p_start_marker ? animation - > get_marker_time ( p_start_marker ) : - 1 ;
double end_time = p_end_marker ? animation - > get_marker_time ( p_end_marker ) : - 1 ;
ERR_FAIL_COND_MSG ( p_start_marker & & p_end_marker & & Animation : : is_greater_approx ( start_time , end_time ) , vformat ( " End marker %s is placed earlier than start marker %s in animation: %s. " , p_end_marker , p_start_marker , name ) ) ;
if ( p_start_marker & & Animation : : is_less_approx ( start_time , 0 ) ) {
WARN_PRINT_ED ( vformat ( " Negative time start marker: %s is invalid in the section, so the start of the animation: %s is used instead. " , p_start_marker , playback . current . from - > animation - > get_name ( ) ) ) ;
}
if ( p_end_marker & & Animation : : is_less_approx ( end_time , 0 ) ) {
WARN_PRINT_ED ( vformat ( " Negative time end marker: %s is invalid in the section, so the end of the animation: %s is used instead. " , p_end_marker , playback . current . from - > animation - > get_name ( ) ) ) ;
}
play_section ( name , start_time , end_time , p_custom_blend , p_custom_scale , p_from_end ) ;
}
void AnimationPlayer : : play_section ( const StringName & p_name , double p_start_time , double p_end_time , double p_custom_blend , float p_custom_scale , bool p_from_end ) {
StringName name = p_name ;
if ( name = = StringName ( ) ) {
name = playback . assigned ;
}
ERR_FAIL_COND_MSG ( ! animation_set . has ( name ) , vformat ( " Animation not found: %s. " , name ) ) ;
ERR_FAIL_COND_MSG ( p_start_time > = 0 & & p_end_time > = 0 & & Math : : is_equal_approx ( p_start_time , p_end_time ) , " Start time and end time must not equal to each other. " ) ;
ERR_FAIL_COND_MSG ( p_start_time > = 0 & & p_end_time > = 0 & & Animation : : is_greater_approx ( p_start_time , p_end_time ) , vformat ( " Start time %f is greater than end time %f. " , p_start_time , p_end_time ) ) ;
2017-03-05 16:44:50 +01:00
Playback & c = playback ;
2014-02-10 02:10:30 +01:00
if ( c . current . from ) {
2022-09-22 15:54:15 +02:00
double blend_time = 0.0 ;
2023-07-20 17:34:06 +02:00
// Find if it can blend.
2014-02-10 02:10:30 +01:00
BlendKey bk ;
2017-03-05 16:44:50 +01:00
bk . from = c . current . from - > name ;
bk . to = name ;
2014-02-10 02:10:30 +01:00
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_or_equal_approx ( p_custom_blend , 0 ) ) {
2017-03-05 16:44:50 +01:00
blend_time = p_custom_blend ;
2014-02-10 02:10:30 +01:00
} else if ( blend_times . has ( bk ) ) {
2017-03-05 16:44:50 +01:00
blend_time = blend_times [ bk ] ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
bk . from = " * " ;
2014-02-10 02:10:30 +01:00
if ( blend_times . has ( bk ) ) {
2017-03-05 16:44:50 +01:00
blend_time = blend_times [ bk ] ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
bk . from = c . current . from - > name ;
bk . to = " * " ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( blend_times . has ( bk ) ) {
2017-03-05 16:44:50 +01:00
blend_time = blend_times [ bk ] ;
2014-02-10 02:10:30 +01:00
}
}
}
2016-03-09 00:00:52 +01:00
2024-07-23 18:00:42 +02:00
if ( Animation : : is_less_approx ( p_custom_blend , 0 ) & & Math : : is_zero_approx ( blend_time ) & & default_blend_time ) {
2017-03-05 16:44:50 +01:00
blend_time = default_blend_time ;
2020-05-14 16:41:43 +02:00
}
2024-07-23 18:00:42 +02:00
if ( Animation : : is_greater_approx ( blend_time , 0 ) ) {
2014-02-10 02:10:30 +01:00
Blend b ;
2017-03-05 16:44:50 +01:00
b . data = c . current ;
2023-12-16 01:42:48 +01:00
b . blend_left = get_current_blend_amount ( ) ;
2023-07-20 17:34:06 +02:00
b . blend_time = blend_time ;
2016-03-09 00:00:52 +01:00
c . blend . push_back ( b ) ;
2019-11-13 04:16:13 +01:00
} else {
c . blend . clear ( ) ;
2014-02-10 02:10:30 +01:00
}
}
2016-03-09 00:00:52 +01:00
2019-08-19 13:48:19 +02:00
if ( get_current_animation ( ) ! = p_name ) {
2024-01-05 18:40:58 +01:00
_clear_playing_caches ( ) ;
2019-08-19 13:48:19 +02:00
}
2018-06-07 17:46:14 +02:00
2017-03-05 16:44:50 +01:00
c . current . from = & animation_set [ name ] ;
2023-10-06 08:47:10 +02:00
c . current . speed_scale = p_custom_scale ;
2024-08-31 08:57:34 +02:00
c . current . start_time = p_start_time ;
c . current . end_time = p_end_time ;
double start = get_section_start_time ( ) ;
double end = get_section_end_time ( ) ;
2023-10-06 08:47:10 +02:00
if ( ! end_reached ) {
playback_queue . clear ( ) ;
}
2019-02-13 18:40:22 +01:00
2023-07-20 17:34:06 +02:00
if ( c . assigned ! = name ) { // Reset.
2024-08-31 08:57:34 +02:00
c . current . pos = p_from_end ? end : start ;
2023-10-06 08:47:10 +02:00
c . assigned = name ;
emit_signal ( SNAME ( " current_animation_changed " ) , c . assigned ) ;
2019-02-20 19:58:53 +01:00
} else {
2024-08-31 08:57:34 +02:00
if ( p_from_end & & Math : : is_equal_approx ( c . current . pos , start ) ) {
2023-07-20 17:34:06 +02:00
// Animation reset but played backwards, set position to the end.
2024-08-31 08:57:34 +02:00
seek_internal ( end , true , true , true ) ;
} else if ( ! p_from_end & & Math : : is_equal_approx ( c . current . pos , end ) ) {
2023-07-20 17:34:06 +02:00
// Animation resumed but already ended, set position to the beginning.
2024-08-31 08:57:34 +02:00
seek_internal ( start , true , true , true ) ;
2023-10-06 08:47:10 +02:00
} else if ( playing ) {
return ;
2019-02-20 19:58:53 +01:00
}
2019-02-13 18:40:22 +01:00
}
2018-06-07 17:46:14 +02:00
c . seeked = false ;
c . started = true ;
2014-02-10 02:10:30 +01:00
2023-07-20 17:34:06 +02:00
_set_process ( true ) ; // Always process when starting an animation.
2014-02-10 02:10:30 +01:00
playing = true ;
2016-05-21 15:29:25 +02:00
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( animation_started ) , c . assigned ) ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( is_inside_tree ( ) & & Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2023-07-20 17:34:06 +02:00
return ; // No next in this case.
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
StringName next = animation_get_next ( p_name ) ;
if ( next ! = StringName ( ) & & animation_set . has ( next ) ) {
2014-02-10 02:10:30 +01:00
queue ( next ) ;
}
}
2024-05-02 04:23:11 +02:00
void AnimationPlayer : : _capture ( const StringName & p_name , bool p_from_end , double p_duration , Tween : : TransitionType p_trans_type , Tween : : EaseType p_ease_type ) {
StringName name = p_name ;
if ( name = = StringName ( ) ) {
name = playback . assigned ;
}
Ref < Animation > anim = get_animation ( name ) ;
if ( anim . is_null ( ) | | ! anim - > is_capture_included ( ) ) {
return ;
}
if ( signbit ( p_duration ) ) {
double max_dur = 0 ;
double current_pos = playback . current . pos ;
if ( playback . assigned ! = name ) {
current_pos = p_from_end ? anim - > get_length ( ) : 0 ;
}
for ( int i = 0 ; i < anim - > get_track_count ( ) ; i + + ) {
if ( anim - > track_get_type ( i ) ! = Animation : : TYPE_VALUE ) {
continue ;
}
if ( anim - > value_track_get_update_mode ( i ) ! = Animation : : UPDATE_CAPTURE ) {
continue ;
}
if ( anim - > track_get_key_count ( i ) = = 0 ) {
continue ;
}
max_dur = MAX ( max_dur , p_from_end ? current_pos - anim - > track_get_key_time ( i , anim - > track_get_key_count ( i ) - 1 ) : anim - > track_get_key_time ( i , 0 ) - current_pos ) ;
}
p_duration = max_dur ;
}
if ( Math : : is_zero_approx ( p_duration ) ) {
return ;
}
capture ( name , p_duration , p_trans_type , p_ease_type ) ;
}
void AnimationPlayer : : play_with_capture ( const StringName & p_name , double p_duration , double p_custom_blend , float p_custom_scale , bool p_from_end , Tween : : TransitionType p_trans_type , Tween : : EaseType p_ease_type ) {
_capture ( p_name , p_from_end , p_duration , p_trans_type , p_ease_type ) ;
_play ( p_name , p_custom_blend , p_custom_scale , p_from_end ) ;
}
2014-02-10 02:10:30 +01:00
bool AnimationPlayer : : is_playing ( ) const {
2017-03-05 16:44:50 +01:00
return playing ;
2014-02-10 02:10:30 +01:00
}
2018-01-14 11:28:57 +01:00
2023-07-20 17:34:06 +02:00
void AnimationPlayer : : set_current_animation ( const String & p_animation ) {
if ( p_animation = = " [stop] " | | p_animation . is_empty ( ) ) {
2018-01-11 23:35:12 +01:00
stop ( ) ;
2023-01-21 06:51:03 +01:00
} else if ( ! is_playing ( ) ) {
2023-07-20 17:34:06 +02:00
play ( p_animation ) ;
} else if ( playback . assigned ! = p_animation ) {
2023-05-26 07:11:29 +02:00
float speed = playback . current . speed_scale ;
2023-07-20 17:34:06 +02:00
play ( p_animation , - 1.0 , speed , signbit ( speed ) ) ;
2014-02-10 02:10:30 +01:00
} else {
2023-07-20 17:34:06 +02:00
// Same animation, do not replay from start.
2014-02-10 02:10:30 +01:00
}
}
String AnimationPlayer : : get_current_animation ( ) const {
2018-01-11 23:35:12 +01:00
return ( is_playing ( ) ? playback . assigned : " " ) ;
2014-02-10 02:10:30 +01:00
}
2023-07-20 17:34:06 +02:00
void AnimationPlayer : : set_assigned_animation ( const String & p_animation ) {
2018-01-14 11:28:57 +01:00
if ( is_playing ( ) ) {
2023-05-26 07:11:29 +02:00
float speed = playback . current . speed_scale ;
2023-07-20 17:34:06 +02:00
play ( p_animation , - 1.0 , speed , signbit ( speed ) ) ;
2018-01-14 11:28:57 +01:00
} else {
2023-07-20 17:34:06 +02:00
ERR_FAIL_COND_MSG ( ! animation_set . has ( p_animation ) , vformat ( " Animation not found: %s. " , p_animation ) ) ;
2018-01-14 11:28:57 +01:00
playback . current . pos = 0 ;
2023-07-20 17:34:06 +02:00
playback . current . from = & animation_set [ p_animation ] ;
2024-08-31 08:57:34 +02:00
playback . current . start_time = - 1 ;
playback . current . end_time = - 1 ;
2023-07-20 17:34:06 +02:00
playback . assigned = p_animation ;
emit_signal ( SNAME ( " current_animation_changed " ) , playback . assigned ) ;
2018-01-14 11:28:57 +01:00
}
}
String AnimationPlayer : : get_assigned_animation ( ) const {
return playback . assigned ;
}
2023-01-11 13:39:39 +01:00
void AnimationPlayer : : pause ( ) {
2023-01-18 14:02:04 +01:00
_stop_internal ( false , false ) ;
2023-01-11 13:39:39 +01:00
}
2023-01-18 14:02:04 +01:00
void AnimationPlayer : : stop ( bool p_keep_state ) {
_stop_internal ( true , p_keep_state ) ;
2014-02-10 02:10:30 +01:00
}
2017-01-13 23:36:04 +01:00
void AnimationPlayer : : set_speed_scale ( float p_speed ) {
2017-03-05 16:44:50 +01:00
speed_scale = p_speed ;
2014-02-10 02:10:30 +01:00
}
2020-05-14 14:29:06 +02:00
2017-01-13 23:36:04 +01:00
float AnimationPlayer : : get_speed_scale ( ) const {
2014-02-10 02:10:30 +01:00
return speed_scale ;
}
2020-05-14 14:29:06 +02:00
2018-03-01 19:52:00 +01:00
float AnimationPlayer : : get_playing_speed ( ) const {
if ( ! playing ) {
return 0 ;
}
return speed_scale * playback . current . speed_scale ;
}
2014-02-10 02:10:30 +01:00
2024-07-16 07:38:56 +02:00
void AnimationPlayer : : seek_internal ( double p_time , bool p_update , bool p_update_only , bool p_is_internal_seek ) {
2023-07-20 17:34:06 +02:00
if ( ! active ) {
return ;
}
2024-07-23 18:00:42 +02:00
bool is_backward = Animation : : is_less_approx ( p_time , playback . current . pos ) ;
2024-06-07 10:51:19 +02:00
2023-11-25 22:28:22 +01:00
_check_immediately_after_start ( ) ;
2023-01-30 15:23:18 +01:00
2023-11-25 22:28:22 +01:00
playback . current . pos = p_time ;
2014-02-10 02:10:30 +01:00
if ( ! playback . current . from ) {
2018-01-11 23:35:12 +01:00
if ( playback . assigned ) {
2022-05-14 18:54:14 +02:00
ERR_FAIL_COND_MSG ( ! animation_set . has ( playback . assigned ) , vformat ( " Animation not found: %s. " , playback . assigned ) ) ;
2018-01-11 23:35:12 +01:00
playback . current . from = & animation_set [ playback . assigned ] ;
}
2023-01-30 15:23:18 +01:00
if ( ! playback . current . from ) {
return ; // There is no animation.
}
2014-02-10 02:10:30 +01:00
}
2024-08-31 08:57:34 +02:00
double start = get_section_start_time ( ) ;
double end = get_section_end_time ( ) ;
// Clamp the seek position.
p_time = CLAMP ( p_time , start , end ) ;
2018-06-07 17:46:14 +02:00
playback . seeked = true ;
2024-07-16 07:38:56 +02:00
playback . internal_seeked = p_is_internal_seek ;
2014-02-10 02:10:30 +01:00
if ( p_update ) {
2024-06-07 10:51:19 +02:00
_process_animation ( is_backward ? - 0.0 : 0.0 , p_update_only ) ;
2023-11-22 15:08:21 +01:00
playback . seeked = false ; // If animation was proceeded here, no more seek in internal process.
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2024-07-16 07:38:56 +02:00
void AnimationPlayer : : seek ( double p_time , bool p_update , bool p_update_only ) {
seek_internal ( p_time , p_update , p_update_only ) ;
}
2023-11-22 15:08:21 +01:00
void AnimationPlayer : : advance ( double p_time ) {
2023-11-25 22:28:22 +01:00
_check_immediately_after_start ( ) ;
2023-11-22 15:08:21 +01:00
AnimationMixer : : advance ( p_time ) ;
}
2023-11-25 22:28:22 +01:00
void AnimationPlayer : : _check_immediately_after_start ( ) {
if ( playback . started ) {
_process_animation ( 0 ) ; // Force process current key for Discrete/Method/Audio/AnimationPlayback. Then, started flag is cleared.
}
}
2014-02-10 02:10:30 +01:00
bool AnimationPlayer : : is_valid ( ) const {
return ( playback . current . from ) ;
}
2022-09-22 15:54:15 +02:00
double AnimationPlayer : : get_current_animation_position ( ) const {
2023-09-28 11:40:18 +02:00
ERR_FAIL_NULL_V_MSG ( playback . current . from , 0 , " AnimationPlayer has no current animation. " ) ;
2014-02-10 02:10:30 +01:00
return playback . current . pos ;
}
2022-09-22 15:54:15 +02:00
double AnimationPlayer : : get_current_animation_length ( ) const {
2023-09-28 11:40:18 +02:00
ERR_FAIL_NULL_V_MSG ( playback . current . from , 0 , " AnimationPlayer has no current animation. " ) ;
2014-02-10 02:10:30 +01:00
return playback . current . from - > animation - > get_length ( ) ;
}
2024-08-31 08:57:34 +02:00
void AnimationPlayer : : set_section_with_markers ( const StringName & p_start_marker , const StringName & p_end_marker ) {
ERR_FAIL_NULL_MSG ( playback . current . from , " AnimationPlayer has no current animation. " ) ;
ERR_FAIL_COND_MSG ( p_start_marker = = p_end_marker & & p_start_marker , vformat ( " Start marker and end marker cannot be the same marker: %s. " , p_start_marker ) ) ;
ERR_FAIL_COND_MSG ( p_start_marker & & ! playback . current . from - > animation - > has_marker ( p_start_marker ) , vformat ( " Marker %s not found in animation: %s. " , p_start_marker , playback . current . from - > animation - > get_name ( ) ) ) ;
ERR_FAIL_COND_MSG ( p_end_marker & & ! playback . current . from - > animation - > has_marker ( p_end_marker ) , vformat ( " Marker %s not found in animation: %s. " , p_end_marker , playback . current . from - > animation - > get_name ( ) ) ) ;
double start_time = p_start_marker ? playback . current . from - > animation - > get_marker_time ( p_start_marker ) : - 1 ;
double end_time = p_end_marker ? playback . current . from - > animation - > get_marker_time ( p_end_marker ) : - 1 ;
if ( p_start_marker & & Animation : : is_less_approx ( start_time , 0 ) ) {
WARN_PRINT_ONCE_ED ( vformat ( " Marker %s time must be positive in animation: %s. " , p_start_marker , playback . current . from - > animation - > get_name ( ) ) ) ;
}
if ( p_end_marker & & Animation : : is_less_approx ( end_time , 0 ) ) {
WARN_PRINT_ONCE_ED ( vformat ( " Marker %s time must be positive in animation: %s. " , p_end_marker , playback . current . from - > animation - > get_name ( ) ) ) ;
}
set_section ( start_time , end_time ) ;
}
void AnimationPlayer : : set_section ( double p_start_time , double p_end_time ) {
ERR_FAIL_NULL_MSG ( playback . current . from , " AnimationPlayer has no current animation. " ) ;
ERR_FAIL_COND_MSG ( Animation : : is_greater_or_equal_approx ( p_start_time , 0 ) & & Animation : : is_greater_or_equal_approx ( p_end_time , 0 ) & & Animation : : is_greater_or_equal_approx ( p_start_time , p_end_time ) , vformat ( " Start time %f is greater than end time %f. " , p_start_time , p_end_time ) ) ;
playback . current . start_time = p_start_time ;
playback . current . end_time = p_end_time ;
playback . current . pos = CLAMP ( playback . current . pos , get_section_start_time ( ) , get_section_end_time ( ) ) ;
}
void AnimationPlayer : : reset_section ( ) {
playback . current . start_time = - 1 ;
playback . current . end_time = - 1 ;
}
double AnimationPlayer : : get_section_start_time ( ) const {
ERR_FAIL_NULL_V_MSG ( playback . current . from , playback . current . start_time , " AnimationPlayer has no current animation. " ) ;
if ( Animation : : is_less_approx ( playback . current . start_time , 0 ) | | playback . current . start_time > playback . current . from - > animation - > get_length ( ) ) {
return 0 ;
}
return playback . current . start_time ;
}
double AnimationPlayer : : get_section_end_time ( ) const {
ERR_FAIL_NULL_V_MSG ( playback . current . from , playback . current . end_time , " AnimationPlayer has no current animation. " ) ;
if ( Animation : : is_less_approx ( playback . current . end_time , 0 ) | | playback . current . end_time > playback . current . from - > animation - > get_length ( ) ) {
return playback . current . from - > animation - > get_length ( ) ;
}
return playback . current . end_time ;
}
bool AnimationPlayer : : has_section ( ) const {
return Animation : : is_greater_or_equal_approx ( playback . current . start_time , 0 ) | | Animation : : is_greater_or_equal_approx ( playback . current . end_time , 0 ) ;
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : set_autoplay ( const String & p_name ) {
2020-05-14 16:41:43 +02:00
if ( is_inside_tree ( ) & & ! Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2018-10-05 00:09:53 +02:00
WARN_PRINT ( " Setting autoplay after the node has been added to the scene has no effect. " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
autoplay = p_name ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
String AnimationPlayer : : get_autoplay ( ) const {
2014-02-10 02:10:30 +01:00
return autoplay ;
}
2022-06-26 01:38:20 +02:00
void AnimationPlayer : : set_movie_quit_on_finish_enabled ( bool p_enabled ) {
movie_quit_on_finish = p_enabled ;
}
bool AnimationPlayer : : is_movie_quit_on_finish_enabled ( ) const {
return movie_quit_on_finish ;
}
2023-01-18 14:02:04 +01:00
void AnimationPlayer : : _stop_internal ( bool p_reset , bool p_keep_state ) {
2023-07-20 17:34:06 +02:00
_clear_caches ( ) ;
2023-01-11 13:39:39 +01:00
Playback & c = playback ;
2023-07-20 17:34:06 +02:00
// c.blend.clear();
2024-10-03 10:59:36 +02:00
double start = c . current . from ? get_section_start_time ( ) : 0 ;
2023-01-11 13:39:39 +01:00
if ( p_reset ) {
2023-07-20 17:34:06 +02:00
c . blend . clear ( ) ;
2023-01-18 14:02:04 +01:00
if ( p_keep_state ) {
2024-08-31 08:57:34 +02:00
c . current . pos = start ;
2023-01-18 14:02:04 +01:00
} else {
is_stopping = true ;
2024-08-31 08:57:34 +02:00
seek_internal ( start , true , true , true ) ;
2023-01-18 14:02:04 +01:00
is_stopping = false ;
}
2023-01-11 13:39:39 +01:00
c . current . from = nullptr ;
c . current . speed_scale = 1 ;
2023-07-20 17:34:06 +02:00
emit_signal ( SNAME ( " current_animation_changed " ) , " " ) ;
2023-01-11 13:39:39 +01:00
}
_set_process ( false ) ;
2023-07-20 17:34:06 +02:00
playback_queue . clear ( ) ;
2023-01-11 13:39:39 +01:00
playing = false ;
}
2017-03-05 16:44:50 +01:00
void AnimationPlayer : : animation_set_next ( const StringName & p_animation , const StringName & p_next ) {
2022-05-14 18:54:14 +02:00
ERR_FAIL_COND_MSG ( ! animation_set . has ( p_animation ) , vformat ( " Animation not found: %s. " , p_animation ) ) ;
2023-07-20 17:34:06 +02:00
animation_next_set [ p_animation ] = p_next ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
StringName AnimationPlayer : : animation_get_next ( const StringName & p_animation ) const {
2023-07-20 17:34:06 +02:00
if ( ! animation_next_set . has ( p_animation ) ) {
2014-02-10 02:10:30 +01:00
return StringName ( ) ;
2020-05-14 16:41:43 +02:00
}
2023-07-20 17:34:06 +02:00
return animation_next_set [ p_animation ] ;
2014-02-10 02:10:30 +01:00
}
2022-09-22 15:54:15 +02:00
void AnimationPlayer : : set_default_blend_time ( double p_default ) {
2017-03-05 16:44:50 +01:00
default_blend_time = p_default ;
2014-02-10 02:10:30 +01:00
}
2022-09-22 15:54:15 +02:00
double AnimationPlayer : : get_default_blend_time ( ) const {
2017-03-05 16:44:50 +01:00
return default_blend_time ;
2014-02-10 02:10:30 +01:00
}
2023-07-20 17:34:06 +02:00
void AnimationPlayer : : set_blend_time ( const StringName & p_animation1 , const StringName & p_animation2 , double p_time ) {
ERR_FAIL_COND_MSG ( ! animation_set . has ( p_animation1 ) , vformat ( " Animation not found: %s. " , p_animation1 ) ) ;
ERR_FAIL_COND_MSG ( ! animation_set . has ( p_animation2 ) , vformat ( " Animation not found: %s. " , p_animation2 ) ) ;
ERR_FAIL_COND_MSG ( p_time < 0 , " Blend time cannot be smaller than 0. " ) ;
BlendKey bk ;
bk . from = p_animation1 ;
bk . to = p_animation2 ;
2024-07-23 18:00:42 +02:00
if ( Math : : is_zero_approx ( p_time ) ) {
2023-07-20 17:34:06 +02:00
blend_times . erase ( bk ) ;
} else {
blend_times [ bk ] = p_time ;
}
2014-02-10 02:10:30 +01:00
}
2023-07-20 17:34:06 +02:00
double AnimationPlayer : : get_blend_time ( const StringName & p_animation1 , const StringName & p_animation2 ) const {
BlendKey bk ;
bk . from = p_animation1 ;
bk . to = p_animation2 ;
if ( blend_times . has ( bk ) ) {
return blend_times [ bk ] ;
} else {
return 0 ;
}
2014-02-10 02:10:30 +01:00
}
2024-05-02 04:23:11 +02:00
void AnimationPlayer : : set_auto_capture ( bool p_auto_capture ) {
auto_capture = p_auto_capture ;
2024-05-02 22:36:36 +02:00
notify_property_list_changed ( ) ;
2024-05-02 04:23:11 +02:00
}
bool AnimationPlayer : : is_auto_capture ( ) const {
return auto_capture ;
}
2024-05-02 22:36:36 +02:00
void AnimationPlayer : : set_auto_capture_duration ( double p_auto_capture_duration ) {
auto_capture_duration = p_auto_capture_duration ;
}
double AnimationPlayer : : get_auto_capture_duration ( ) const {
return auto_capture_duration ;
}
void AnimationPlayer : : set_auto_capture_transition_type ( Tween : : TransitionType p_auto_capture_transition_type ) {
auto_capture_transition_type = p_auto_capture_transition_type ;
}
Tween : : TransitionType AnimationPlayer : : get_auto_capture_transition_type ( ) const {
return auto_capture_transition_type ;
}
void AnimationPlayer : : set_auto_capture_ease_type ( Tween : : EaseType p_auto_capture_ease_type ) {
auto_capture_ease_type = p_auto_capture_ease_type ;
}
Tween : : EaseType AnimationPlayer : : get_auto_capture_ease_type ( ) const {
return auto_capture_ease_type ;
}
2023-07-20 17:34:06 +02:00
void AnimationPlayer : : _animation_removed ( const StringName & p_name , const StringName & p_library ) {
AnimationMixer : : _animation_removed ( p_name , p_library ) ;
2017-11-01 21:32:39 +01:00
2023-07-20 17:34:06 +02:00
StringName name = p_library = = StringName ( ) ? p_name : StringName ( String ( p_library ) + " / " + String ( p_name ) ) ;
2017-11-01 21:32:39 +01:00
2023-07-20 17:34:06 +02:00
if ( ! animation_set . has ( name ) ) {
return ; // No need to update because not the one from the library being used.
}
2017-11-01 21:32:39 +01:00
2023-07-20 17:34:06 +02:00
_animation_set_cache_update ( ) ;
2017-11-01 21:32:39 +01:00
2023-07-20 17:34:06 +02:00
// Erase blends if needed
List < BlendKey > to_erase ;
for ( const KeyValue < BlendKey , double > & E : blend_times ) {
BlendKey bk = E . key ;
if ( bk . from = = name | | bk . to = = name ) {
to_erase . push_back ( bk ) ;
2017-11-01 21:32:39 +01:00
}
}
2023-07-20 17:34:06 +02:00
while ( to_erase . size ( ) ) {
blend_times . erase ( to_erase . front ( ) - > get ( ) ) ;
to_erase . pop_front ( ) ;
}
2017-11-01 21:32:39 +01:00
}
2023-07-20 17:34:06 +02:00
void AnimationPlayer : : _rename_animation ( const StringName & p_from_name , const StringName & p_to_name ) {
AnimationMixer : : _rename_animation ( p_from_name , p_to_name ) ;
// Rename autoplay or blends if needed.
List < BlendKey > to_erase ;
HashMap < BlendKey , double , BlendKey > to_insert ;
for ( const KeyValue < BlendKey , double > & E : blend_times ) {
BlendKey bk = E . key ;
BlendKey new_bk = bk ;
bool erase = false ;
if ( bk . from = = p_from_name ) {
new_bk . from = p_to_name ;
erase = true ;
}
if ( bk . to = = p_from_name ) {
new_bk . to = p_to_name ;
erase = true ;
}
if ( erase ) {
to_erase . push_back ( bk ) ;
to_insert [ new_bk ] = E . value ;
}
2017-11-01 21:32:39 +01:00
}
2020-12-20 11:46:44 +01:00
2023-07-20 17:34:06 +02:00
while ( to_erase . size ( ) ) {
blend_times . erase ( to_erase . front ( ) - > get ( ) ) ;
to_erase . pop_front ( ) ;
}
while ( to_insert . size ( ) ) {
blend_times [ to_insert . begin ( ) - > key ] = to_insert . begin ( ) - > value ;
to_insert . remove ( to_insert . begin ( ) ) ;
}
2020-12-20 11:46:44 +01:00
2023-07-20 17:34:06 +02:00
if ( autoplay = = p_from_name ) {
autoplay = p_to_name ;
}
2017-11-01 21:32:39 +01:00
}
2014-02-10 02:10:30 +01:00
void AnimationPlayer : : _bind_methods ( ) {
2023-07-20 17:34:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " animation_set_next " , " animation_from " , " animation_to " ) , & AnimationPlayer : : animation_set_next ) ;
ClassDB : : bind_method ( D_METHOD ( " animation_get_next " , " animation_from " ) , & AnimationPlayer : : animation_get_next ) ;
2016-05-07 18:27:52 +02:00
2023-07-20 17:34:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_blend_time " , " animation_from " , " animation_to " , " sec " ) , & AnimationPlayer : : set_blend_time ) ;
ClassDB : : bind_method ( D_METHOD ( " get_blend_time " , " animation_from " , " animation_to " ) , & AnimationPlayer : : get_blend_time ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_default_blend_time " , " sec " ) , & AnimationPlayer : : set_default_blend_time ) ;
ClassDB : : bind_method ( D_METHOD ( " get_default_blend_time " ) , & AnimationPlayer : : get_default_blend_time ) ;
2014-02-10 02:10:30 +01:00
2024-05-02 04:23:11 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_auto_capture " , " auto_capture " ) , & AnimationPlayer : : set_auto_capture ) ;
ClassDB : : bind_method ( D_METHOD ( " is_auto_capture " ) , & AnimationPlayer : : is_auto_capture ) ;
2024-05-02 22:36:36 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_auto_capture_duration " , " auto_capture_duration " ) , & AnimationPlayer : : set_auto_capture_duration ) ;
ClassDB : : bind_method ( D_METHOD ( " get_auto_capture_duration " ) , & AnimationPlayer : : get_auto_capture_duration ) ;
ClassDB : : bind_method ( D_METHOD ( " set_auto_capture_transition_type " , " auto_capture_transition_type " ) , & AnimationPlayer : : set_auto_capture_transition_type ) ;
ClassDB : : bind_method ( D_METHOD ( " get_auto_capture_transition_type " ) , & AnimationPlayer : : get_auto_capture_transition_type ) ;
ClassDB : : bind_method ( D_METHOD ( " set_auto_capture_ease_type " , " auto_capture_ease_type " ) , & AnimationPlayer : : set_auto_capture_ease_type ) ;
ClassDB : : bind_method ( D_METHOD ( " get_auto_capture_ease_type " ) , & AnimationPlayer : : get_auto_capture_ease_type ) ;
2024-05-02 04:23:11 +02:00
2024-01-30 21:03:28 +01:00
ClassDB : : bind_method ( D_METHOD ( " play " , " name " , " custom_blend " , " custom_speed " , " from_end " ) , & AnimationPlayer : : play , DEFVAL ( StringName ( ) ) , DEFVAL ( - 1 ) , DEFVAL ( 1.0 ) , DEFVAL ( false ) ) ;
2024-08-31 08:57:34 +02:00
ClassDB : : bind_method ( D_METHOD ( " play_section_with_markers " , " name " , " start_marker " , " end_marker " , " custom_blend " , " custom_speed " , " from_end " ) , & AnimationPlayer : : play_section_with_markers , DEFVAL ( StringName ( ) ) , DEFVAL ( StringName ( ) ) , DEFVAL ( StringName ( ) ) , DEFVAL ( - 1 ) , DEFVAL ( 1.0 ) , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " play_section " , " name " , " start_time " , " end_time " , " custom_blend " , " custom_speed " , " from_end " ) , & AnimationPlayer : : play_section , DEFVAL ( StringName ( ) ) , DEFVAL ( - 1 ) , DEFVAL ( - 1 ) , DEFVAL ( - 1 ) , DEFVAL ( 1.0 ) , DEFVAL ( false ) ) ;
2024-01-30 21:03:28 +01:00
ClassDB : : bind_method ( D_METHOD ( " play_backwards " , " name " , " custom_blend " ) , & AnimationPlayer : : play_backwards , DEFVAL ( StringName ( ) ) , DEFVAL ( - 1 ) ) ;
2024-08-31 08:57:34 +02:00
ClassDB : : bind_method ( D_METHOD ( " play_section_with_markers_backwards " , " name " , " start_marker " , " end_marker " , " custom_blend " ) , & AnimationPlayer : : play_section_with_markers_backwards , DEFVAL ( StringName ( ) ) , DEFVAL ( StringName ( ) ) , DEFVAL ( StringName ( ) ) , DEFVAL ( - 1 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " play_section_backwards " , " name " , " start_time " , " end_time " , " custom_blend " ) , & AnimationPlayer : : play_section_backwards , DEFVAL ( StringName ( ) ) , DEFVAL ( - 1 ) , DEFVAL ( - 1 ) , DEFVAL ( - 1 ) ) ;
2024-05-02 04:23:11 +02:00
ClassDB : : bind_method ( D_METHOD ( " play_with_capture " , " name " , " duration " , " custom_blend " , " custom_speed " , " from_end " , " trans_type " , " ease_type " ) , & AnimationPlayer : : play_with_capture , DEFVAL ( StringName ( ) ) , DEFVAL ( - 1.0 ) , DEFVAL ( - 1 ) , DEFVAL ( 1.0 ) , DEFVAL ( false ) , DEFVAL ( Tween : : TRANS_LINEAR ) , DEFVAL ( Tween : : EASE_IN ) ) ;
2023-01-11 13:39:39 +01:00
ClassDB : : bind_method ( D_METHOD ( " pause " ) , & AnimationPlayer : : pause ) ;
2023-01-18 14:02:04 +01:00
ClassDB : : bind_method ( D_METHOD ( " stop " , " keep_state " ) , & AnimationPlayer : : stop , DEFVAL ( false ) ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_playing " ) , & AnimationPlayer : : is_playing ) ;
2017-12-14 00:07:39 +01:00
2023-07-20 17:34:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_current_animation " , " animation " ) , & AnimationPlayer : : set_current_animation ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_current_animation " ) , & AnimationPlayer : : get_current_animation ) ;
2023-07-20 17:34:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_assigned_animation " , " animation " ) , & AnimationPlayer : : set_assigned_animation ) ;
2018-01-14 11:28:57 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_assigned_animation " ) , & AnimationPlayer : : get_assigned_animation ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " queue " , " name " ) , & AnimationPlayer : : queue ) ;
2018-11-28 01:43:34 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_queue " ) , & AnimationPlayer : : get_queue ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear_queue " ) , & AnimationPlayer : : clear_queue ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_speed_scale " , " speed " ) , & AnimationPlayer : : set_speed_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " get_speed_scale " ) , & AnimationPlayer : : get_speed_scale ) ;
2018-03-01 19:52:00 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_playing_speed " ) , & AnimationPlayer : : get_playing_speed ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_autoplay " , " name " ) , & AnimationPlayer : : set_autoplay ) ;
ClassDB : : bind_method ( D_METHOD ( " get_autoplay " ) , & AnimationPlayer : : get_autoplay ) ;
2014-02-10 02:10:30 +01:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " find_animation " , " animation " ) , & AnimationPlayer : : find_animation ) ;
2022-04-07 13:49:28 +02:00
ClassDB : : bind_method ( D_METHOD ( " find_animation_library " , " animation " ) , & AnimationPlayer : : find_animation_library ) ;
2014-02-10 02:10:30 +01:00
2022-08-08 14:18:26 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_movie_quit_on_finish_enabled " , " enabled " ) , & AnimationPlayer : : set_movie_quit_on_finish_enabled ) ;
2022-06-26 01:38:20 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_movie_quit_on_finish_enabled " ) , & AnimationPlayer : : is_movie_quit_on_finish_enabled ) ;
2017-12-07 18:19:21 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_current_animation_position " ) , & AnimationPlayer : : get_current_animation_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_current_animation_length " ) , & AnimationPlayer : : get_current_animation_length ) ;
2024-08-31 08:57:34 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_section_with_markers " , " start_marker " , " end_marker " ) , & AnimationPlayer : : set_section_with_markers , DEFVAL ( StringName ( ) ) , DEFVAL ( StringName ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " set_section " , " start_time " , " end_time " ) , & AnimationPlayer : : set_section , DEFVAL ( - 1 ) , DEFVAL ( - 1 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " reset_section " ) , & AnimationPlayer : : reset_section ) ;
ClassDB : : bind_method ( D_METHOD ( " get_section_start_time " ) , & AnimationPlayer : : get_section_start_time ) ;
ClassDB : : bind_method ( D_METHOD ( " get_section_end_time " ) , & AnimationPlayer : : get_section_end_time ) ;
ClassDB : : bind_method ( D_METHOD ( " has_section " ) , & AnimationPlayer : : has_section ) ;
2023-07-20 17:34:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " seek " , " seconds " , " update " , " update_only " ) , & AnimationPlayer : : seek , DEFVAL ( false ) , DEFVAL ( false ) ) ;
2023-01-19 16:43:37 +01:00
2022-11-29 10:51:45 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " current_animation " , PROPERTY_HINT_ENUM , " " , PROPERTY_USAGE_EDITOR ) , " set_current_animation " , " get_current_animation " ) ;
2021-06-18 01:10:18 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " assigned_animation " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " set_assigned_animation " , " get_assigned_animation " ) ;
2021-11-03 23:06:17 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " autoplay " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR ) , " set_autoplay " , " get_autoplay " ) ;
2021-06-18 01:10:18 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " current_animation_length " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " " , " get_current_animation_length " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " current_animation_position " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " " , " get_current_animation_position " ) ;
2018-01-11 23:35:12 +01:00
2017-08-07 03:51:56 +02:00
ADD_GROUP ( " Playback Options " , " playback_ " ) ;
2024-05-02 04:23:11 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " playback_auto_capture " ) , " set_auto_capture " , " is_auto_capture " ) ;
2024-05-02 22:36:36 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " playback_auto_capture_duration " , PROPERTY_HINT_NONE , " suffix:s " ) , " set_auto_capture_duration " , " get_auto_capture_duration " ) ;
2024-09-14 23:42:04 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " playback_auto_capture_transition_type " , PROPERTY_HINT_ENUM , " Linear,Sine,Quint,Quart,Quad,Expo,Elastic,Cubic,Circ,Bounce,Back,Spring " ) , " set_auto_capture_transition_type " , " get_auto_capture_transition_type " ) ;
2024-05-02 22:36:36 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " playback_auto_capture_ease_type " , PROPERTY_HINT_ENUM , " In,Out,InOut,OutIn " ) , " set_auto_capture_ease_type " , " get_auto_capture_ease_type " ) ;
2022-05-20 07:24:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " playback_default_blend_time " , PROPERTY_HINT_RANGE , " 0,4096,0.01,suffix:s " ) , " set_default_blend_time " , " get_default_blend_time " ) ;
2014-02-10 02:10:30 +01:00
2023-10-01 20:23:31 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " speed_scale " , PROPERTY_HINT_RANGE , " -4,4,0.001,or_less,or_greater " ) , " set_speed_scale " , " get_speed_scale " ) ;
2022-06-26 01:38:20 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " movie_quit_on_finish " ) , " set_movie_quit_on_finish_enabled " , " is_movie_quit_on_finish_enabled " ) ;
2023-07-20 17:34:06 +02:00
ADD_SIGNAL ( MethodInfo ( SNAME ( " current_animation_changed " ) , PropertyInfo ( Variant : : STRING , " name " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( SNAME ( " animation_changed " ) , PropertyInfo ( Variant : : STRING_NAME , " old_name " ) , PropertyInfo ( Variant : : STRING_NAME , " new_name " ) ) ) ;
2014-02-10 02:10:30 +01:00
}
AnimationPlayer : : AnimationPlayer ( ) {
}
2017-03-05 16:44:50 +01:00
AnimationPlayer : : ~ AnimationPlayer ( ) {
2014-02-10 02:10:30 +01:00
}