gale.state module

This file contains the implementation of the classes BaseState, StateMachine, HierarchicalState, and StateStack. These classes are used to create a state machine that can change between states.

Author: Alejandro Mujica (aledrums@gmail.com)

class gale.state.BaseState(state_machine)[source]

Bases: object

This class represents an empty state. Any state machines will start in this state.

It also is the base for any state. You should extend this class to implement any new state class.

Parameters:

state_machine (StateMachine)

enter(*args, **kwargs)[source]

Method to be executed when the state machine enters in the state.

Parameters:
  • args (Tuple[Any])

  • kwargs (Dict[str, Any])

Return type:

None

exit()[source]

Method to be executed when the state machine exits from the state.

Return type:

None

on_input(input_id, input_data)[source]
Parameters:
  • input_id (str)

  • input_data (InputData)

Return type:

None

update(dt)[source]
Parameters:

dt (float)

Return type:

None

render(surface)[source]
Parameters:

surface (Surface)

Return type:

None

class gale.state.StateMachine(states=None)[source]

Bases: object

The state machine.

Usage: States are instantiated when they are set to the attribute ‘current’. They are passed to the constructor as a dictionary argument containing pairs either (state_name, StateClass) or (state_name, function_to_build_state).

It is expected that added states contain the methods: enter, exit, update, and render. It is recommended creating states by inheriting from BaseState in base_state module.

Example

state_machine = StateMachine({

‘start’: StartState, ‘play’: lambda sm: return PlayState(sm)

}) state_machine.change(‘start’)

Parameters:

states (Dict[str, BaseState] | None)

change(state_name, *args, **kwargs)[source]

Change the state of the machine.

Parameters:
  • state_name (str) – The name of the state that will be set.

  • args (Tuple[Any])

  • kwargs (Dict[str, Any])

Return type:

None

*args and **kwargs: Any argument list of keyword arguments that are accepted by the enter method of the new state.

Raises:

KeyError – If the arg state_name is not as a key in the states dictionary.

Parameters:
  • state_name (str)

  • args (Tuple[Any])

  • kwargs (Dict[str, Any])

Return type:

None

on_input(input_id, input_data)[source]

Call the method on_input of the current state of the machine.

Parameters:
  • input_id (str) – The string that describes the input.

  • input_data (InputData) – Data associated to the input type.

Return type:

None

update(dt)[source]

Call to update of the current state of the machine.

Parameters:

dt (float) – Time elapsed of the game loop.

Return type:

None

render(surface)[source]

Call to render of the current state of the machine.

Parameters:

surface (Surface) – The surface where the state should be rendered on.

Return type:

None

class gale.state.HierarchicalState(state_machine, substates=None, initial_substate=None)[source]

Bases: BaseState

A state that owns a nested StateMachine (its “substate machine”).

A HierarchicalState is a regular state from the point of view of the StateMachine (or StateStack) that owns it – it can be added to a ‘states’ dictionary and driven through enter/exit/on_input/update/render just like any other BaseState – but it also behaves as the root of a sub-machine: entering it can select a default substate, and its on_input/update/render delegate down to whichever substate is currently active in that sub-machine.

This is enough to build a hierarchical state machine (HFSM): a “superstate” is simply a HierarchicalState whose substates are BaseState (or, recursively, HierarchicalState) instances. Nesting composes for free: a substate that is itself a HierarchicalState will delegate down to its own substate machine in turn, so arbitrarily deep hierarchies require no extra machinery.

Usage: Subclasses that override enter, on_input, update, or render and still want the substate machine to be driven MUST call the corresponding super().foo(…) method (typically first). Subclasses that do not override these methods inherit the delegation directly, so they nest correctly with no extra code.

Example

class Walking(BaseState):
def update(self, dt: float) -> None:

… # move towards the next waypoint

class LookingAround(BaseState):
def update(self, dt: float) -> None:

… # rotate in place scanning the surroundings

class Patrol(HierarchicalState):
def __init__(self, state_machine: StateMachine) -> None:
super().__init__(

state_machine, substates={“walking”: Walking, “looking_around”: LookingAround}, initial_substate=”walking”,

)

def update(self, dt: float) -> None:

super().update(dt) if self.reached_waypoint():

self.change_substate(“looking_around”)

guard_fsm = StateMachine({“patrol”: Patrol, “alert”: Alert}) guard_fsm.change(“patrol”)

Parameters:
enter(*args, **kwargs)[source]

Select the initial substate, if one was configured, forwarding any received arguments to its enter method.

Parameters:
  • kwargs (Dict[str, Any]) – Any argument list or keyword arguments

  • args (Tuple[Any])

  • kwargs

Return type:

None

accepted by the initial substate’s enter method.

change_substate(state_name, *args, **kwargs)[source]

Change the state of the nested substate machine.

Parameters:
  • state_name (str) – The name of the substate that will be set.

  • kwargs (Dict[str, Any]) – Any argument list or keyword arguments

  • args (Tuple[Any])

  • kwargs

Return type:

None

accepted by the enter method of the new substate.

Raises:

KeyError – If state_name is not a key in the substates

Parameters:
  • state_name (str)

  • args (Tuple[Any])

  • kwargs (Dict[str, Any])

Return type:

None

dictionary.

on_input(input_id, input_data)[source]

Delegate on_input to the current substate of the substate machine.

Parameters:
  • input_id (str) – The string that describes the input.

  • input_data (InputData) – Data associated to the input type.

Return type:

None

update(dt)[source]

Delegate update to the current substate of the substate machine.

Parameters:

dt (float) – Time elapsed of the game loop.

Return type:

None

render(surface)[source]

Delegate render to the current substate of the substate machine.

Parameters:

surface (Surface) – The surface where the state should be rendered on.

Return type:

None

class gale.state.StateStack[source]

Bases: object

Class to stack states. It renders all of then but it only updates the top state.

Usage: The stack is created empty. States are pushed to the stack and popped from it.

state_stack = StateStack() state_stack.push(state1) state_stack.push(state2) state_stack.pop()

on_input(input_id, input_data)[source]

Call the method on_input of the top state of the stack.

Parameters:
  • input_id (str) – The string that describes the input.

  • input_data (InputData) – Data associated to the input type.

Return type:

None

update(dt)[source]

Call to update of the top state of the stack.

Parameters:

dt (float) – Time elapsed of the game loop.

Raises:

RuntimeError – If the stack is empty.

Return type:

None

render(surface)[source]

Call to render all of the states in the stack.

Parameters:

surface (Surface) – The surface where the state should be rendered on.

Return type:

None

clear()[source]

Clear the stack.

Return type:

None

push(state, *args, **kwargs)[source]

Add a new state on the top of the stack.

Parameters:
  • state (BaseState) – The state to be added based on BaseState.

  • args (Tuple[Any])

  • kwargs (Dict[str, Any])

*args and **kwargsargs and **kwargs:

Any argument list of keyword arguments that are accepted by the enter method of the new state.

Return type:

None

pop()[source]

Remove the top state of the stack.

Raises:

RuntimeError – If the stack is empty.

Return type:

None