(Godot Engine) Setting AnimationPlayer key values to current values

Viewed 1342

How would it be possible to set an animation's key value to the current value of the Object that is referenced in the animation, similarly to passing null to the initial_val and / or final_val arguments of an Tween Node?

"Setting the initial value to null uses the current value of the property." Tween Node Documentation

My answer is the current approach that I have tried, but I fear it's too convoluted.

2 Answers

With this method, I can set an already existing animation's key values to the specified track position _animation_position with the current values of the Nodes specified in the argument _node_names and optionally, an specific property of that node passed in _property_names, else, all properties present in the animation and related to the Node will be altered.

func Animation_Set_Current_Values(_animation_player: AnimationPlayer, _animation_name: String = "", _animation_position: int = 0,
_node_names: Array = [], _property_names: Array = [], _disable_unwanted: bool = true, _play_animation: bool = true) -> void:
    if not _node_names.empty():
        if not _animation_player.get_animation_list().empty():
            # Use the first animation in the animation player if no animation name is specified for convenience
            var _detected_animation_name: String = _animation_name if (
                not _animation_name.empty() and _animation_player.has_animation(_animation_name)) else _animation_player.get_animation_list()[0]
            var _animation: Animation = _animation_player.get_animation(_detected_animation_name)
            # Store detected track / node information: Node_Name: [{_property: _track_count}, ...]
            var _track_data: Dictionary = {}
            if _animation.get_track_count() != 0:
                for _track in _animation.get_track_count():
                    var _track_path: NodePath = _animation.track_get_path(_track)
                    var _node_path: String = (_track_path as String).split(":")[0]
                    var _node_property: String = (_track_path as String).split(":")[1]
                    var _node: Object = _animation_player.get_parent().get_node(_node_path)
                    if _node != null:
                        if not _track_data.has(_node): _track_data[_node] = []
                        _track_data[_node].append({_node_property: _track})
                        if _disable_unwanted: _animation.track_set_enabled(_track, false)
            # Set track keys values to the current initial values
            if not _track_data.empty():
                for _track_data_node in _track_data.keys():
                    if _node_names.has(_track_data_node.name):
                        for _track_data_property in _track_data[_track_data_node]:
                            var _track_data_property_name: String = _track_data_property.keys().front()
                            var _track_data_property_track_idx: int = _track_data_property.values().front()
                            var _node_property = _track_data_node.get(_track_data_property_name)
                            if _node_property != null:
                                if _property_names.has(_track_data_property_name) or _property_names.empty():
                                    if _animation_position <= _animation.track_get_key_count(_track_data_property_track_idx) - 1:
                                        _animation.track_set_key_value(_track_data_property_track_idx, _animation_position, _node_property)
                                        _animation.track_set_enabled(_track_data_property_track_idx, true)
            # Optionally, play the animation if specified
            if _play_animation: _animation_player.play(_detected_animation_name)

properly transitioning two animations in the following scenario: considering an character swinging a sword, there are two animations: "swing" and "parry", if I play the "parry" animation while the "swing" animation is still in process

You have two animations and you want to blend between them. Which is not what you asked (XY problem).

Using the AnimationPlayer, you can specify transition times between any two animations. Including an animation and itself, which happens when you tell Godot to play an animation while that same animation is playing.

In the animation panel (in the bottom of the editor), with the first animation selected ("swing" in your example), click on the "Animation" button and select "Edit Transitions". It will open the Cross-Animation Blend Times dialog for that selected animation.

The dialog will show all the animations with a number attached, 0 by default. That is the time in which Godot will blend the animation, in seconds.

The 0 (default) means instantaneous. That is, if you play another animation ("parry" in your example), it will snap to the start values of that animation… Which is not what you want. Instead increase the time.

Note that Godot will not interpolate to the start values of the new animation, it will interpolate to the current values of the new animation playing.


To reiterate the scenario, while the first animation (say "swing") is playing, you play the second animation (say "parry").

The second animation plays, but the values set will not be those in the animation. Instead they will be some interpolation between the current values and those in the animation. The interpolation will be such that at the start the current value is unaltered, and after whatever time you configured in the Cross-Animation Blend Times dialog, the value is what is in the animation.

And yes, that is a linear interpolation. At least as far as I can tell, keep in mind that we rarely want the transition to be long.


If you replace the initial values of an animation with the current values, then the animation would meet values of the animation at the second key frame.

You can make the transition time match the second key frame instead. Not exactly the same, given that you can have tracks with key frames at different times that do not line up, and you can control how each track interpolates. However the approach I present here is much less work (no code at all).


If you don't want a linear interpolation, or you want to interpolate between more than two animations, please use an AnimationTree. See also Controlling animation states.

Related