derkork / godot-statecharts

A state charts extension for Godot 4
MIT License
679 stars 33 forks source link

Can the evaluation of the Guard's expression be postponed until after the Delay Second time has ended? #123

Closed BravoNiceCatch closed 1 month ago

BravoNiceCatch commented 1 month ago

image image image

In my Godot project, there's a smaller entity "Enemy" and a larger one "WatchMan." The WatchMan has two states: "Idle" and "Observing." When the Enemy enters the WatchMan's area, the state switches to "Observing," and it reverts to "Idle" when the Enemy exits. This functionality works perfectly until I introduced a 2-second delay on the to "To Idle" node and used "not enemy_in_observing_area" as the Guard Expression. The issue arises when the Enemy enters the WatchMan's range, leaves, and then reenters within those 2 seconds—the state still changes to "Idle," even though the Guard Expression evaluates to false at that point.

It seems the Guard Expression is checked before the delay starts. I'm curious about the design choice behind this and whether it's feasible to evaluate the Guard Expression after the delay concludes, considering its value might change during the delay period.

derkork commented 1 month ago

Guards are always evaluated when the transition is triggered and once the evaluation succeeds, the transition is comitted and will run. However during the delay time the transition is pending and while it is pending, you still have the option to perform another transition which will overrule the pending transition. With this knowledge, you can build the desired behaviour even without having any guard in place:

image

image

image

This approach is both simpler, as you don't need any expression property to track whether the enemy is currently in range and its also cheaper as you don't pay for guard evaluations every frame.

BravoNiceCatch commented 1 month ago

@derkork Thank you very much, I realize I overcomplicated the issue. Simply adding another transition back to the Observing state while already in the Observing state would suffice. image