Hello, I’m currently in the process of making a new enemy and experimenting with some new stuff in AnimationTreeStateMachine to see if it could simplify my code.
I’ve been trying to use nested AnimationTreeStateMachines to make the animation flowchart easier to comprehend/read.
Here is my node setup (the disconnected animations are just placeholders to show what’s inside the statemachines):
I’ve also been attempting to use expressions instead of conditions to transition between states/animations.
This animation setup works basically like any other setup. Suppose the enemy is in either the run, idle or attack animation. In that case, they can at any point (and from any of the aforementioned animations) switch to either the stunned state or the damaged state machine. Provided the advance expression is met, and vice versa.
The issue
So here is the issue, currently while the enemy is attacking the player, if the player then interrupts the enemy by attacking it, the enemy hurt animation cancels/interrupts the attack animation.
This makes it possible for the player to run up to the enemy, spam attack and kill it before it can even attack
It would be fine, ok if the player could interrupt the enemy once, but as long as it’s not possible to quickly run up and kill the enemy without any resistance
Question
How can I temporarily stop the enemy from transitioning from the attack state to the hurt state?
Feel free to ask for more information if necessary
Any and all help is appreciated
Looks like you are using an advance condition or expression so you’ll need to delay the transition between attack and hurt in code somehow (like with a Timer)
#hurt transition is the expression that switches from the movement state machine to the damaged state machine
if hurt_transition == true:
timer.start()
if timer.time_left:
animation_tree.set_advance_mode(0) #disabled
else:
animation_tree.set_advance_mode(2) #auto
But the set advance mode returns the error
“Invalid call. Nonexistent function ‘set_advance_mode’ in base ‘AnimationTree’.”
I probably need to declare my statemachine as a variable and use that as a base instead but I’m not really sure how to do that. And I also think that since a specific transition isn’t specified it’ll just default to all the transitions
I’m not sure how I should proceed from here
If you don’t want to use either mechanism and do it manually with AnimationNodeStateMachinePlayback.travel() the documentation of that class has an example on how to interact with it.
var state_machine = $AnimationTree.get("parameters/playback")
state_machine.travel("some_state")
I’m using expressions to transition between states.
the code adjustments didn’t quite work although this is because the original idea was flawed since hurt transition would always equate to false.
So I changed it to this:
if timer.time_left:
hurt_transition = false
func _on_animation_tree_animation_finished(anim_name):
if (anim_name == "hurt") and hurt_transition == true:
timer.start()
So that now the hurt animation will play and then after it’s finished the the hurt_transition variable will prevent the transition from happening until the timer is finished.
Although now the player can keep force triggering the hurt animation by spamming attack
Should I make the hurt animation shorter than the attack animation? or do you know if there is a way to forcibly make the animation finish first (I tried changing the transition switch to “at end” but that just broke the enemy for some reason)
Well, if you are using advance expressions then you have full control on when the transition will happen then. It’s up to you. Like, for example, don’t re-trigger the hurt transition until some time has passed since the last hurt transition.
Thats what I’m trying to do with the timer.
The hurt transition is triggered everytime the player hits the enemy (and the enemy takes damage) then the timer should start and prevent the hurt transition from triggering again.
The issue now (i should prbably have mentioned this before) is that the transition from being hurt back to movement is defined by !hurt_transition.
Since movement also includes the attack animation it’s hard to check for something like velocity or something else so I decided to check for not the state it is coming from of the other states
Uhm, maybe you should move out to the main state machine the attack and hurt states so you can have more control on the transitions that happen between those states and the rest.
You can call functions that return a boolean directly in the advance expression. You can then go as complex as you need inside them.
Nvm the timer never started because the hurt animation transitioned prematurely due to some animation settings it works now
Thank you so much for the help!