godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.82k stars 21.14k forks source link

Replacing AnimationNodeStateMachine in AnimationNodeBlendTree during runtime breaks animation #88262

Open xand00 opened 8 months ago

xand00 commented 8 months ago

Tested versions

Reproducible in Godot 4.3 dev 3, Godot v4.2.1.stable

System information

Godot v4.2.1.stable - Windows 10.0.22621 - Vulkan (Forward+) - dedicated Radeon RX 590 Series (Advanced Micro Devices, Inc.; 31.0.21902.5) - 12th Gen Intel(R) Core(TM) i5-12400F (12 Threads)

Issue description

I have such AnimationTree root_node: image

I want to replace AnimationNodeStateMachine with another AnimationNodeStateMachine during runtime

I tried exporting my moveset

@onready var animator : AnimationTree = $AnimationTree
@export var moveset: AnimationNodeStateMachine

and then replace it and reconnect with my blend node but i get t-pose

var previous_position: Vector2 = animator.tree_root.get_node_position("moveset_1")
animator.tree_root.remove_node("moveset_1")
animator.tree_root.add_node("moveset_1", moveset, previous_position)
animator.tree_root.connect_node("Blend2", 1, "moveset_1")

also i tried to reconnect node, but it has the same result:

animator.tree_root.disconnect_node("Blend2", 1)
animator.tree_root.connect_node("Blend2", 1, "moveset_2")

Steps to reproduce

attack with LMB change moveset with "C"

If you connect moveset_2 with Blend2 before starting game, then this way animation will change without issues, but if you change moveset with "C", then animation will break

there are two ways in player's script, you can comment current and uncomment other one:

if Input.is_action_just_pressed("change_moveset"):
  #region type 1
  #var previous_position: Vector2 = animator.tree_root.get_node_position("moveset_1")
  #animator.tree_root.remove_node("moveset_1")
  #animator.tree_root.add_node("moveset_1", moveset, previous_position)
  #animator.tree_root.connect_node("Blend2", 1, "moveset_1")
  #endregion

  #region type 2
  animator.tree_root.disconnect_node("Blend2", 1)
  animator.tree_root.connect_node("Blend2", 1, "moveset_2")
  #endregion

Minimal reproduction project (MRP)

Animation Test.zip

TokageItLab commented 7 months ago

Probably, this is due to flush the cache caused by Tree changes.

However, as a basic using, frequent reconnection of nodes is not recommended. In the case of the description, the normal setup to use AnimationTree is to switch between two StateMachines by using NodeTransition.