2014-02-10 02:10:30 +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"
2014-02-10 02:10:30 +01:00
# include "scene/scene_string_names.h"
2017-10-30 19:43:19 +01:00
2014-02-10 02:10:30 +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/ " ) ) {
2015-06-29 05:29:49 +02:00
String which = name . get_slicec ( ' / ' , 1 ) ;
2014-02-10 02:10:30 +01:00
animation_set_next ( which , p_value ) ;
2015-06-29 05:29:49 +02:00
} else if ( p_name = = SceneStringNames : : get_singleton ( ) - > blend_times ) {
2014-02-10 02:10:30 +01:00
Array array = p_value ;
int len = array . size ( ) ;
ERR_FAIL_COND_V ( len % 3 , false ) ;
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 ) ;
}
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 ;
}
bool AnimationPlayer : : _get ( const StringName & p_name , Variant & r_ret ) const {
String name = p_name ;
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/ " ) ) {
2015-06-29 05:29:49 +02:00
String which = name . get_slicec ( ' / ' , 1 ) ;
2014-02-10 02:10:30 +01:00
r_ret = animation_get_next ( which ) ;
} else if ( name = = " 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 ;
for ( int i = 0 ; i < keys . size ( ) ; i + + ) {
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
}
2014-02-10 02:10:30 +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 ;
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 ) {
switch ( p_what ) {
case NOTIFICATION_READY : {
2017-08-19 01:02:56 +02:00
if ( ! Engine : : get_singleton ( ) - > is_editor_hint ( ) & & animation_set . has ( autoplay ) ) {
2023-07-20 17:34:06 +02:00
set_active ( true ) ;
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 ;
}
}
2023-07-20 17:34:06 +02:00
void AnimationPlayer : : _process_playback_data ( PlaybackData & cd , double p_delta , float p_blend , bool p_seeked , bool p_started , bool p_is_current ) {
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
2021-08-10 00:15:17 +02:00
real_t len = cd . from - > animation - > get_length ( ) ;
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 : {
2021-10-15 15:25:00 +02:00
if ( next_pos < 0 ) {
next_pos = 0 ;
} else if ( next_pos > len ) {
next_pos = len ;
}
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 : {
2022-11-29 10:51:45 +01:00
if ( next_pos < 0 & & cd . pos > = 0 ) {
looped_flag = Animation : : LOOPED_FLAG_START ;
2014-02-10 02:10:30 +01:00
}
2022-11-29 10:51:45 +01:00
if ( next_pos > len & & cd . pos < = len ) {
looped_flag = Animation : : LOOPED_FLAG_END ;
}
next_pos = Math : : fposmod ( next_pos , ( double ) len ) ;
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 : {
2022-11-29 10:51:45 +01:00
if ( next_pos < 0 & & cd . pos > = 0 ) {
cd . speed_scale * = - 1.0 ;
looped_flag = Animation : : LOOPED_FLAG_START ;
2021-04-24 22:47:03 +02:00
}
2022-11-29 10:51:45 +01:00
if ( next_pos > len & & cd . pos < = len ) {
cd . speed_scale * = - 1.0 ;
looped_flag = Animation : : LOOPED_FLAG_END ;
2021-10-15 15:25:00 +02:00
}
2022-11-29 10:51:45 +01:00
next_pos = Math : : pingpong ( next_pos , ( double ) len ) ;
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.
2014-02-10 02:10:30 +01:00
cd . pos = next_pos ;
2022-12-07 10:28:36 +01:00
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 ) {
if ( ! backwards & & prev_pos < = len & & next_pos = = len ) {
// Playback finished.
end_reached = true ;
end_notify = prev_pos < len ; // Notify only if not already at the end.
p_blend = 1.0 ;
2023-01-27 19:25:49 +01:00
}
2023-07-20 17:34:06 +02:00
if ( backwards & & prev_pos > = 0 & & next_pos = = 0 ) {
// Playback finished.
end_reached = true ;
end_notify = prev_pos > 0 ; // Notify only if not already at the beginning.
p_blend = 1.0 ;
2023-01-27 19:25:49 +01:00
}
}
}
2014-02-10 02:10:30 +01:00
2023-07-20 17:34:06 +02:00
PlaybackInfo pi ;
if ( p_started ) {
pi . time = prev_pos ;
pi . delta = 0 ;
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 ;
pi . seeked = p_seeked ;
2022-04-07 13:49:28 +02:00
}
2023-12-16 06:19:50 +01:00
// AnimationPlayer doesn't have internal seeking.
// However, 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_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.
2022-04-07 13:49:28 +02:00
2023-07-20 17:34:06 +02:00
if ( p_delta ! = 0 ) {
c . seeked = false ;
}
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.
2023-12-16 01:42:48 +01:00
_process_playback_data ( c . current , p_delta , get_current_blend_amount ( ) , 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 ) ;
2023-07-20 17:34:06 +02:00
if ( b . blend_left < = 0 ) {
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.
_process_playback_data ( b . data , p_delta , b . blend_left , 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 ) {
emit_signal ( SceneStringNames : : get_singleton ( ) - > animation_changed , old , new_name ) ;
}
} else {
_clear_caches ( ) ;
playing = false ;
_set_process ( false ) ;
if ( end_notify ) {
emit_signal ( SceneStringNames : : get_singleton ( ) - > animation_finished , playback . assigned ) ;
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
}
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 ) {
2015-09-10 05:10:54 +02:00
play ( p_name , p_custom_blend , - 1 , true ) ;
}
2024-01-05 18:40:58 +01:00
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 ) {
StringName name = p_name ;
if ( name = = StringName ( ) ) {
name = playback . assigned ;
}
if ( signbit ( p_duration ) ) {
double max_dur = 0 ;
Ref < Animation > anim = get_animation ( name ) ;
if ( anim . is_valid ( ) ) {
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 ;
}
capture ( name , p_duration , p_trans_type , p_ease_type ) ;
play ( name , p_custom_blend , p_custom_scale , p_from_end ) ;
}
2022-09-22 15:54:15 +02:00
void AnimationPlayer : : play ( const StringName & p_name , double p_custom_blend , float p_custom_scale , bool p_from_end ) {
2014-02-10 02:10:30 +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 ( ) ) {
2014-02-10 02:10:30 +01:00
name = playback . assigned ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2024-01-05 18:40:58 +01:00
# ifdef TOOLS_ENABLED
if ( ! Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
bool warn_enabled = false ;
if ( capture_cache . animation . is_null ( ) ) {
Ref < Animation > anim = get_animation ( name ) ;
if ( anim . is_valid ( ) ) {
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 ;
}
warn_enabled = true ;
}
}
}
if ( warn_enabled ) {
WARN_PRINT_ONCE_ED ( " Capture track found. If you want to interpolate animation with captured frame, you can use play_with_capture() instead of play(). " ) ;
}
}
# endif
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
2014-02-10 02:10:30 +01:00
Playback & c = playback ;
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 ;
bk . from = c . current . from - > name ;
bk . to = name ;
if ( p_custom_blend > = 0 ) {
blend_time = p_custom_blend ;
} else if ( blend_times . has ( bk ) ) {
blend_time = blend_times [ bk ] ;
} else {
bk . from = " * " ;
if ( blend_times . has ( bk ) ) {
blend_time = blend_times [ bk ] ;
} else {
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 ) ) {
blend_time = blend_times [ bk ] ;
}
}
}
2016-03-09 00:00:52 +01:00
2020-05-14 16:41:43 +02:00
if ( p_custom_blend < 0 & & blend_time = = 0 & & default_blend_time ) {
2014-02-10 02:10:30 +01:00
blend_time = default_blend_time ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
if ( blend_time > 0 ) {
Blend b ;
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
2014-02-10 02:10:30 +01:00
c . current . from = & animation_set [ name ] ;
2023-10-06 08:47:10 +02:00
c . current . speed_scale = p_custom_scale ;
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.
2019-02-13 18:40:22 +01:00
c . current . pos = p_from_end ? c . current . from - > animation - > get_length ( ) : 0 ;
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 {
if ( p_from_end & & c . current . pos = = 0 ) {
2023-07-20 17:34:06 +02:00
// Animation reset but played backwards, set position to the end.
2019-02-20 19:58:53 +01:00
c . current . pos = c . current . from - > animation - > get_length ( ) ;
} else if ( ! p_from_end & & c . current . pos = = c . current . from - > animation - > get_length ( ) ) {
2023-07-20 17:34:06 +02:00
// Animation resumed but already ended, set position to the beginning.
2019-02-20 19:58:53 +01:00
c . current . pos = 0 ;
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
2016-04-14 17:19:20 +02:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > 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
StringName next = animation_get_next ( p_name ) ;
2014-10-28 02:54:32 +01:00
if ( next ! = StringName ( ) & & animation_set . has ( next ) ) {
2014-02-10 02:10:30 +01:00
queue ( next ) ;
}
}
bool AnimationPlayer : : is_playing ( ) const {
return playing ;
}
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 ] ;
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 ) {
2014-02-10 02:10:30 +01:00
speed_scale = p_speed ;
}
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
2023-07-20 17:34:06 +02:00
void AnimationPlayer : : seek ( double p_time , bool p_update , bool p_update_only ) {
if ( ! active ) {
return ;
}
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
}
2018-06-07 17:46:14 +02:00
playback . seeked = true ;
2014-02-10 02:10:30 +01:00
if ( p_update ) {
2023-07-20 17:34:06 +02:00
_process_animation ( 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
}
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 ( ) ;
}
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
autoplay = p_name ;
}
String AnimationPlayer : : get_autoplay ( ) const {
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();
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 ) {
c . current . pos = 0 ;
} else {
is_stopping = true ;
2023-07-20 17:34:06 +02:00
seek ( 0 , 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 ;
}
2014-02-10 02:10:30 +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
}
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 ) {
2014-02-10 02:10:30 +01:00
default_blend_time = p_default ;
}
2022-09-22 15:54:15 +02:00
double AnimationPlayer : : get_default_blend_time ( ) const {
2014-02-10 02:10:30 +01:00
return default_blend_time ;
}
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 ;
if ( p_time = = 0 ) {
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-01-03 12:10:11 +01:00
# ifdef TOOLS_ENABLED
2014-12-17 02:31:57 +01:00
void AnimationPlayer : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2024-01-03 12:10:11 +01:00
const String pf = p_function ;
if ( p_idx = = 0 & & ( pf = = " play " | | pf = = " play_backwards " | | pf = = " has_animation " | | pf = = " queue " ) ) {
2014-12-17 02:31:57 +01:00
List < StringName > al ;
get_animation_list ( & al ) ;
2021-08-13 21:24:02 +02:00
for ( const StringName & name : al ) {
2021-10-01 17:06:48 +02:00
r_options - > push_back ( String ( name ) . quote ( ) ) ;
2014-12-17 02:31:57 +01:00
}
}
2024-01-03 00:13:04 +01:00
AnimationMixer : : get_argument_options ( p_function , p_idx , r_options ) ;
2014-12-17 02:31:57 +01:00
}
2024-01-03 12:10:11 +01:00
# endif
2014-02-10 02:10:30 +01:00
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-02-13 12:47:24 +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-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 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " play_backwards " , " name " , " custom_blend " ) , & AnimationPlayer : : play_backwards , DEFVAL ( StringName ( ) ) , DEFVAL ( - 1 ) ) ;
2024-01-05 18:40:58 +01: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 ( - 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-02-13 12:47:24 +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-02-13 12:47:24 +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-02-13 12:47:24 +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-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear_queue " ) , & AnimationPlayer : : clear_queue ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +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-02-13 12:47:24 +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 ) ;
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_ " ) ;
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 ( ) {
}
AnimationPlayer : : ~ AnimationPlayer ( ) {
}