derkork / godot-statecharts

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

Run check on automatic transitions on state change #114

Open derkork opened 2 months ago

derkork commented 2 months ago

Currently automatic transitions will be evaluated whenever you enter a state, send an event or set an expression property. However we also have a guard that checks if a certain state is active and people are regularly confused about why the guard checking an expression property will be evaluated whenever we change an expression property, but the guard checking for a state being active is not checked when a state change happens.

The state charts "specification" is somewhat vague on when exactly automatic transitions are checked:

If a machine is in a state with a guarded automatic transition, then that guard is checked as often as possible. Being event driven, the guards are effectively only checked whenever an event has been processed, but also after other automatic transitions have fired, or other internal events (such as raised events) are fired

On one hand we have "as often as possible" which indicates we don't even need a trigger and should check them basically every frame, on the other hand there are specific occasions given.

If we lean more towards the former, then any change to the state of a state chart (actual states and expression properties) and the sending of any event would trigger the evaluation of automatic transitions.

derkork commented 2 months ago

This change will not be backwards compatible, so this needs to have some section in the manual and changelog. I also need some examples of flows that are broken by this change.

derkork commented 1 month ago

This has proven to be extremely tricky. There are tons of edge cases where you end up in endless loops because any transition can trigger even more transitions. A particularly nasty example is:

image

Because A stays active all the time, it trigger a state enter/exit repeatedly which will again re-evaluate the transitions. A way to fix this would be to do it like this:

image

This way the DECIDE state would be left immediately after it has decided, thus breaking the loop because both transitions are no longer in play. But I really don't want the library to freeze if someone builds the problematic thing, especially since this thing is probably the first thing someone will come up with..