FSM-rebird with generators ?

Hi,
someone has by chance tryed to use a generator to manage states-fsm?

to me seem cool.
why?

a thing that i hate of states
is the fact that almost ever (we say ever)
it need to 2 steps, an “init” and a “run” (more over for animations but not only)
and this unfortunately require some “name”…

also, often you need to create little variables, functions, references, that are needed for a state
but are not needed for all states.
in other worlds, each state is an exception(well, for that need the state).
all these exception become a mountain of code.
remove some redundancy usually traduct in code less readable.
keep redundancy is anyway prone to mistakes.

generators has differents advantages:
1- microcode (ie, code extremely short vs self.useless.gob.meannothing)
2- initialization(s) : it not need to “names” (ie: wander_init or some other trash as classes placeholder)
it simply can be the “first piece” of code (at the top of it)
3- encapsulation complete.

pseudo code


def fsm_gen(own):
    # we can store all reference that never change
    near = own.sensors["Near"]
    skeleton = own["skeleton"]
    steer = 


    
    #functions
    def myusefulfunc1():
        return own.something()
    def myusefulfunc2():
        return own.something()
    def myusefulfunc3():
        return own.something()




    #states (that are generators too)
    def gg_wander():
        #initialization
        skeleton.playAction(..)
        changeTarget()


        while True:
            if nearTarget(): 
                changeTarget()
            if near.positive:
                yield gg_alerted() #transition
            yield


    
    def gg_alerted():
        skeleton.playAction(..)
        steer.target = None
        alert_value = 200
        while alert_value>0:
            alert_value -= 1
            yield


        yield gg_wander() #transition






    gg = gg_wander() #first state
    # FSM CORE
    
    t = 0
    while True:
        new_gg = next(ggs)
        if new_gg:
            t = 0
            new_gg()
            gg = new_gg
        t += 1




def somechar(cont):
    own = cont.owner
    if not "fsm_gen" in own:
        own["skeleton"] 
        (..)
        own["fsm_gen"] = fsm_gen(own)
    next(own["fsm_gen"])









never dreamed to write something as:


if x > y:
    x = x+y*y
    own.doSomething()

where the x still persistent also the next tic?

what you think?:eyebrowlift:

I have found a system that runs a list of data to be packed into a function call is most efficent, when a command timmer runs out or a goal is achieved, pop the command.

so an action is

[‘command’,Time, [data]]

so you can feed a whole list to an actor and watch em go.
[ [‘navigate’,1200,[TargetActorOrPoint]],[‘dialog’,60,[dialogdata]] ]

etc

I use a dictioary to look up functions then pack the data in the function call

current = commandList[0]
function = dictionary[current[0]]
function(current)

PS: i forget to put a “yield” in the core of FSM (while True)

this seem more a “task manager”.

where you give a list predefinied of tasks
and then wait for the end of task.
to give then the next task of the list.

what happen if an actor while do the task “buy pizza” , has a collision with bullet ? by chance?
how make to change the list?:wink:
or simply cannot happen?

you have the bullet striking, add a new command to the command list, or even remove all actions except 1 you add (flee)

also, you can have main that calls functions, add functions to the list, or bump orders etc.

I can’t follow the above arguments.

I never heard that an FSM need “init” and “run”.
As far as I know state machines have a start (or initial) state.

State machine
The focus of a state machines is on when to transit from one state to another states. It does not care what each single state does as long as the state can be triggered. The states should know what they do. It is the core of the concept that each state has isolated behavior in it’s own. This allows to encapsulate the lower level state behavior from higher level state transition behavior.

A state machine shines when the states are really different to each other. Nethertheless it can handle equal states too.

Example:
“Walking” is very different to “Waiting” or “Grabbing”. They may run similar operations (such as playing animations) but they are assembled completely different.

  • walking = moving collison box + play walkcycle + steering + detecting target position
  • waiting = play idle animation
  • grabbing = play touch animation -> parenting -> play grip animation -> play stand up animation (this can be a state machine of itself)

What you call “Exception” is the benefit of the state machine. You are able to easily manage completely different behavior, without the need to know the details of these behaviors.

It is the same as your TV. It has several states that are completely different too:

  • off
  • standby
  • showing
  • recording
  • configuring

Showing different channels are not states of this state machine. As showing different channels is very similar an FSM is not necessaryily the best choice at that state.

Recording on the other hand can come with it’s own FSM.

  • recording
  • playing
  • pausing
  • stoping
    -> even combinations are possible (playing while recording -> time shift)

When you find the different states do not fit your concept, I guess a state machine is not the best choice in your situation.
When the states are very similar you might look for a different implementation.

I’ve been creating action objects as components of my FSM. They encapsulate all the mechanics of an action in a class. Things like track to, move a certain distance, pathfind to a location or shoot a gun.
The FSM creates the action, then updates it until it is done. A state can consist of several different actions.
It makes it easy to write and execute new states.

Hi,
for the “init” and “run” i mean for the state not for the state-machine.

one thing i not got is -> who should check if the state is ended or if the state “want change” ?

you had made a good example, about the TV.

when the states are sort of “channels” ,
(happen often of have these sort of states to me, not know why :smiley: )
is clear that is the fsm that check,ends channels, and starts another one,
(ie , the caller change setting, rather than the called)
since the conditions for the change of state-channel is not dependent from the state-channel.
(so the state-channel has not info useful)

problem is when conditions for the change-state are dependent completely or in part :confused: from the state

in the bricks seem more similar to this last, ie, is the state that know when change
if sensor -> and -> setState() … this is code that run inside the active state (so, somehow the “called” change the configuration of the “caller”)

my pseudo code is pretty similar to this last case .
(in part ) :rolleyes:

anyway that is a bit offtopic .

the point was moreover that the generators, have the ability to “store the state of the code” ,
that maybe can be exploited somehow , :eyebrowlift:

That will not happen. State changes are completely managed by the state machine, rather than by the state. That makes the state graph so easy to read. You can be sure there are no “secret” paths between the states.

State machines can have four different type of actions:
-> entry action (when entering a state regardless from where)
-> exit action (when leaving the state regardless to what other state)
-> transition action (when transitting from one specific state to another a specifc event)
-> state action (constantly processed while the state is active/current)

The first three are event driven as they only occur on transition (remember you can transit from one state to the same one building a loop).
The last one is less an event as a continual process.

There are special forms of FSMs that limit the action types. E.g. FSMs that have entry actions only or FSMs that have state actions only.

Considering the “init” and “run” operation. The first can be treated as entry action, while the second one would be the state action. Typically you do not need all action types everywhere.

While an action can trigger an event for state transition, it is not up to the state to transit. The FSM performs the transition and ensures all necessary actions are executed within the right order.

The important point is to separate FSM operations (transitions) from lower level state operations (which can be anything even other FSMs).

I can’t recommend to use a “channel” as state. It technically is one (as it holds status of the system).
It requires you to create a huge (dynamic) state graph with lots of states. The sttructure (states and transitions) are always the same. So here it makes more sense to have one operation and use the current channel and available channels as parameter.

With the TV example I want ed to demonstrate the difference between states:

  • showing (showing a live channel)
  • playing (showing a recorded session)
  • recording (recording a live channel)

Look at you TV. In each state(mode) the same buttons have different meanings e.g.:

  • showing <stop> does nothing
  • recording <stop> ends the recording
  • playing <stop> ends playing

while others do the same:

  • showing <volume up> makes it lauder
  • recording <volume up> makes it lauder
  • recording <volume up> makes it lauder

This last example would exclude volume control from the FSM as it is independent to the states unless “standby” is a state too (where volume control is disabled).