Panda3D
Public Member Functions | Public Attributes | Static Public Attributes | List of all members
FSM Class Reference
Inheritance diagram for FSM:
DirectObject Fixture ClassicStyle NewStyle ToonEyes

Public Member Functions

def __init__ (self, name)
 
def __repr__ (self)
 
def __str__ (self)
 
def cleanup (self)
 
def defaultEnter (self, *args)
 
def defaultExit (self)
 
def defaultFilter (self, request, args)
 
def demand (self, request, *args)
 
def filterOff (self, request, args)
 
def forceTransition (self, request, *args)
 
def getCurrentFilter (self)
 
def getCurrentOrNextState (self)
 
def getCurrentStateOrTransition (self)
 
def getStateChangeEvent (self)
 
def isInTransition (self)
 
def request (self, request, *args)
 
def requestNext (self, *args)
 
def requestPrev (self, *args)
 
def setBroadcastStateChanges (self, doBroadcast)
 
def setStateArray (self, stateArray)
 
- Public Member Functions inherited from DirectObject
def __init__ (self)
 
def accept (self, event, method, extraArgs=[])
 
def acceptOnce (self, event, method, extraArgs=[])
 
def addTask (self, *args, **kwargs)
 
def detectLeaks (self)
 
def doMethodLater (self, *args, **kwargs)
 
def getAllAccepting (self)
 
def ignore (self, event)
 
def ignoreAll (self)
 
def isAccepting (self, event)
 
def isIgnoring (self, event)
 
def removeAllTasks (self)
 
def removeTask (self, taskOrName)
 

Public Attributes

 fsmLock
 
 newState
 
 oldState
 
 state
 
 stateArray
 

Static Public Attributes

 defaultTransitions = None
 
 notify = DirectNotifyGlobal.directNotify.newCategory("FSM")
 
int SerialNum = 0
 
- Static Public Attributes inherited from DirectObject
def accept_once = acceptOnce
 
def add_task = addTask
 
def detect_leaks = detectLeaks
 
def do_method_later = doMethodLater
 
def get_all_accepting = getAllAccepting
 
def ignore_all = ignoreAll
 
def is_accepting = isAccepting
 
def is_ignoring = isIgnoring
 
def remove_all_tasks = removeAllTasks
 
def remove_task = removeTask
 

Detailed Description

A Finite State Machine.  This is intended to be the base class
of any number of specific machines, which consist of a collection
of states and transitions, and rules to switch between states
according to arbitrary input data.

The states of an FSM are defined implicitly.  Each state is
identified by a string, which by convention begins with a capital
letter.  (Also by convention, strings passed to request that are
not state names should begin with a lowercase letter.)

To define specialized behavior when entering or exiting a
particular state, define a method named enterState() and/or
exitState(), where "State" is the name of the state, e.g.:

def enterRed(self):
    ... do stuff ...

def exitRed(self):
    ... cleanup stuff ...

def enterYellow(self):
    ... do stuff ...

def exitYellow(self):
    ... cleanup stuff ...

def enterGreen(self):
    ... do stuff ...

def exitGreen(self):
    ... cleanup stuff ...

Both functions can access the previous state name as
self.oldState, and the new state name we are transitioning to as
self.newState.  (Of course, in enterRed(), self.newState will
always be "Red", and the in exitRed(), self.oldState will always
be "Red".)

Both functions are optional.  If either function is omitted, the
state is still defined, but nothing is done when transitioning
into (or out of) the state.

Additionally, you may define a filterState() function for each
state.  The purpose of this function is to decide what state to
transition to next, if any, on receipt of a particular input.  The
input is always a string and a tuple of optional parameters (which
is often empty), and the return value should either be None to do
nothing, or the name of the state to transition into.  For
example:

def filterRed(self, request, args):
    if request in ['Green']:
        return (request,) + args
    return None

def filterYellow(self, request, args):
    if request in ['Red']:
        return (request,) + args
    return None

def filterGreen(self, request, args):
    if request in ['Yellow']:
        return (request,) + args
    return None

As above, the filterState() functions are optional.  If any is
omitted, the defaultFilter() method is called instead.  A standard
implementation of defaultFilter() is provided, which may be
overridden in a derived class to change the behavior on an
unexpected transition.

If self.defaultTransitions is left unassigned, then the standard
implementation of defaultFilter() will return None for any
lowercase transition name and allow any uppercase transition name
(this assumes that an uppercase name is a request to go directly
to a particular state by name).

self.state may be queried at any time other than during the
handling of the enter() and exit() functions.  During these
functions, self.state contains the value None (you are not really
in any state during the transition).  However, during a transition
you *can* query the outgoing and incoming states, respectively,
via self.oldState and self.newState.  At other times, self.state
contains the name of the current state.

Initially, the FSM is in state 'Off'.  It does not call enterOff()
at construction time; it is simply in Off already by convention.
If you need to call code in enterOff() to initialize your FSM
properly, call it explicitly in the constructor.  Similarly, when
cleanup() is called or the FSM is destructed, the FSM transitions
back to 'Off' by convention.  (It does call enterOff() at this
point, but does not call exitOff().)

To implement nested hierarchical FSM's, simply create a nested FSM
and store it on the class within the appropriate enterState()
function, and clean it up within the corresponding exitState()
function.

There is a way to define specialized transition behavior between
two particular states.  This is done by defining a from<X>To<Y>()
function, where X is the old state and Y is the new state.  If this
is defined, it will be run in place of the exit<X> and enter<Y>
functions, so if you want that behavior, you'll have to call them
specifically.  Otherwise, you can completely replace that transition's
behavior.

See the code in SampleFSM.py for further examples.

Constructor & Destructor Documentation

◆ __init__()

def __init__ (   self,
  name 
)

Reimplemented in ClassicStyle.

Member Function Documentation

◆ __repr__()

def __repr__ (   self)

◆ __str__()

def __str__ (   self)
Print out something useful about the fsm

Reimplemented in Fixture.

◆ cleanup()

def cleanup (   self)

◆ defaultEnter()

def defaultEnter (   self,
args 
)
This is the default function that is called if there is no
enterState() method for a particular state name. 

◆ defaultExit()

def defaultExit (   self)
This is the default function that is called if there is no
exitState() method for a particular state name. 

◆ defaultFilter()

def defaultFilter (   self,
  request,
  args 
)
This is the function that is called if there is no
filterState() method for a particular state name.

This default filter function behaves in one of two modes:

(1) if self.defaultTransitions is None, allow any request
whose name begins with a capital letter, which is assumed to
be a direct request to a particular state.  This is similar to
the old ClassicFSM onUndefTransition=ALLOW, with no explicit
state transitions listed.

(2) if self.defaultTransitions is not None, allow only those
requests explicitly identified in this map.  This is similar
to the old ClassicFSM onUndefTransition=DISALLOW, with an
explicit list of allowed state transitions.

Specialized FSM's may wish to redefine this default filter
(for instance, to always return the request itself, thus
allowing any transition.).

Reimplemented in ToonEyes, and Fixture.

◆ demand()

def demand (   self,
  request,
args 
)
Requests a state transition, by code that does not expect
the request to be denied.  If the request is denied, raises a
RequestDenied exception.

Unlike request(), this method allows a new request to be made
while the FSM is currently in transition.  In this case, the
request is queued up and will be executed when the current
transition finishes.  Multiple requests will queue up in
sequence.

◆ filterOff()

def filterOff (   self,
  request,
  args 
)
From the off state, we can always go directly to any other
state.

◆ forceTransition()

def forceTransition (   self,
  request,
args 
)
Changes unconditionally to the indicated state.  This
bypasses the filterState() function, and just calls
exitState() followed by enterState().

◆ getCurrentFilter()

def getCurrentFilter (   self)

◆ getCurrentOrNextState()

def getCurrentOrNextState (   self)

◆ getCurrentStateOrTransition()

def getCurrentStateOrTransition (   self)

◆ getStateChangeEvent()

def getStateChangeEvent (   self)

◆ isInTransition()

def isInTransition (   self)

◆ request()

def request (   self,
  request,
args 
)
Requests a state transition (or other behavior).  The
request may be denied by the FSM's filter function.  If it is
denied, the filter function may either raise an exception
(RequestDenied), or it may simply return None, without
changing the FSM's state.

The request parameter should be a string.  The request, along
with any additional arguments, is passed to the current
filterState() function.  If filterState() returns a string,
the FSM transitions to that state.

The return value is the same as the return value of
filterState() (that is, None if the request does not provoke a
state transition, otherwise it is a tuple containing the name
of the state followed by any optional args.)

If the FSM is currently in transition (i.e. in the middle of
executing an enterState or exitState function), an
AlreadyInTransition exception is raised (but see demand(),
which will queue these requests up and apply when the
transition is complete).

◆ requestNext()

def requestNext (   self,
args 
)
Request the 'next' state in the predefined state array.

◆ requestPrev()

def requestPrev (   self,
args 
)
Request the 'previous' state in the predefined state array.

◆ setBroadcastStateChanges()

def setBroadcastStateChanges (   self,
  doBroadcast 
)

◆ setStateArray()

def setStateArray (   self,
  stateArray 
)
array of unique states to iterate through

Member Data Documentation

◆ defaultTransitions

defaultTransitions = None
static

◆ fsmLock

fsmLock

◆ newState

newState

◆ notify

notify = DirectNotifyGlobal.directNotify.newCategory("FSM")
static

◆ oldState

oldState

◆ SerialNum

int SerialNum = 0
static

◆ state

state

◆ stateArray

stateArray