derkork / godot-statecharts

A state charts extension for Godot 4
MIT License
761 stars 39 forks source link

AnimationFinished Guard #29

Closed Shadowblitz16 closed 1 year ago

Shadowblitz16 commented 1 year ago

I know I asked about this earlier but it would be nice to have a AnimationPlayerFinishedGuard and a AnimationTreeFinishedGuard

derkork commented 1 year ago

How would this guard work? An animation being finished is an event that occurs. A guard is something that is checked before a transition is taken. So the guard would only work if the transition and the finishing of the animation would happen in the same frame, which is rather unlikely.

If you simply want to check if the animation player is still playing an animation before taking a transition, you can set the animation player as an expression property at the start and then use the expression guard for checking, e.g.

@onready var _state_chart:StateChart = $StateChart
@onready var _animation_player:AnimationPlayer = $AnimationPlayer

func _ready():
    _state_chart.set_expression_property("animation_player", _animation_player)

and then in your expression guard:

not animation_player.is_playing()

If you want to take a transition on when the animation player finishes playing an animation listen to the animation_finished event of the animation player and send an event to the state chart, e.g.:

func _on_animation_player_animation_finished(animation):
    _state_chart.send_event("animation_finished")

Then you can set up transitions that react to this event.

Shadowblitz16 commented 1 year ago

you would pass an animation player or tree to the guard and then it would check if it's finished. if false then it would guard the state from transitioning if true it would transition

you could await for it in a while loop and await a process frame every time the while loop executes. if the guard is freed it would exit the while loop

derkork commented 1 year ago

Well yes, this is what I have described you can implement with the expression guard. However I don't really see how such a thing would be generally useful. What is the use case you have for this?

Shadowblitz16 commented 1 year ago

Well yes, this is what I have described you can implement with the expression guard. However I don't really see how such a thing would be generally useful. What is the use case you have for this?

it would be for waiting for a animation state to finish.

derkork commented 1 year ago

Well yes but this is very likely not useful. You would need something to constantly send events that trigger a state change for this guard to have an effect, otherwise it will not do anything. Could you maybe describe the actual problem you want to try to solve with this? Then I think I might give a better recommendation.

Shadowblitz16 commented 1 year ago

I want to wait for a animation to end before starting a new state

derkork commented 1 year ago

Well in this case, hook up the animation_finished signal of the animation player and then let it trigger a state change by sending an event like this:

func _on_animation_player_animation_finished(animation):
    _state_chart.send_event("animation_finished")

And then connect the animation player's animation_finished signal to this function. This should do the trick nicely.