The image shows my previous implementation approach. Even though it's in Chinese, I'll roughly describe it."
First, here are two screenshots of the node tree. Under the Node2D node are the specific animations of the AnimationSprite2D nodes. Under the Node, there’s a bunch of specific states such as Run, Idle, Attack, etc. Their parent node is an overall script that centrally manages the logic.
The remaining three images show my personal implementation of this comprehensive logic management script. One image shows that I created a large number of boolean variables to check various conditions — for example: whether on the ground, whether the movement key is pressed, whether the attack key is pressed, whether in the air, etc. Another image shows the judgment/check functions I wrote specifically for these variables. Most of them are just simple one-line expressions, basically combining those boolean variables in different ways. The last image shows that these functions are executed once every frame (_process)."
Finally, the last image has text written on it — it's the Idle script. Most of the other state-specific scripts follow a similar pattern.
My main implementation logic is as follows: each state script gets the boolean judgment variables from the parent node, initializes them in _ready(), and then follows this unified structure in its every-frame function:
If the condition for Idle is not satisfied, then set the Idle animation's visible = false and return immediately. (Almost all my state scripts start their per-frame function with this same check: if the condition is not met, hide the animation and return.)
If the condition is satisfied, then set the animation visible = true, call play(), and apply some fine-tuning and additional settings depending on the specific state.
(The rest of the states follow basically the same structure as this Idle example.)