Hey BlendingBGE,
I think a finite state machine (FSM) might help you. Basically the idea behind a FSM you have a number of states (idle, running, jumping) and you have transitions between states. Transitions are like conditions such as “if in the idle state and the space bar is pressed, transfer to the jumping state”.
You can visualise a FSM as a flow map, e.g:

They are relatively easy to implement in python, the idea is you represent a state by an ID, such a string “idle”, “walking” and “jumping”. The actual state is a function, e.g:
def idle():
# play idle animation
pass
def walking():
# catch keyboard input
# apply force
# play appropriate animation
pass
def jumping():
# apply upwards force if just entering state
# remove/dampen controls
pass
You want to run the current state each frame and check that if the conditions for any transitions are met then to switch the current state. Transitions require three things, a from state, a to state and the condition. Conditions can be done as functions also:
def if_wasd():
keyboard = bge.logic.keyboard
return (keyboard.events[bge.events.WKEY] == bge.logic.KX_INPUT_ACTIVE or
keyboard.events[bge.events.AKEY] == bge.logic.KX_INPUT_ACTIVE or
keyboard.events[bge.events.SKEY] == bge.logic.KX_INPUT_ACTIVE or
keyboard.events[bge.events.DKEY] == bge.logic.KX_INPUT_ACTIVE)
ect
Heres a simple class to manage the states and transitions of an FSM:
class FiniteStateMachine:
"""Finite State Machine"""
def __init__(self):
self.states = {} # A dictionary of states: identifier -> callable
self.transitions = {} # A dictionary of transistions: from state -> [to state, condition], ...]
self.current_state = None # Identifier of the current state
def add_state(self, state, action=None):
"""Add another state
state - identifier
action - callable, to be run while state is active
"""
self.states[state] = action
self.transitions[state] = []
# Make the new state the current state if its the first one added
if self.current_state is None:
self.current_state = state
def add_transition(self, parent_state, child_state, condition):
""" Add a transistion between states
parent_state: the from state identifier
child_state: the to state identifier
condition: A callable which returns True or False
"""
self.transitions[parent_state].append([child_state, condition])
def main(self):
for transition in self.transitions[self.current_state]:
if transition[1]():
self.current_state = transition[0]
if callable(self.states[self.current_state]):
self.states[self.current_state]()
You add states and transitions to the FSM using the add_state and add_transition methods. The main method checks all conditions on the current state and transitions states if needed, otherwise calls the function assigned to the current state.
To set up your FSM you would just do something like:
own = bge.logic.getCurrentController().owner
def init():
fsm = FiniteStateMachine()
fsm.add_state('idle', idle)
fsm.add_state('walking', walking)
fsm.add_state('jumping', jumping)
fsm.add_transition('idle', 'walking', if_wasd)
fsm.add_transition('idle', 'jumping', if_space)
fsm.add_transition('walking', 'idle', lambda: not if_wasd())
fsm.add_transition('walking', 'jumping', if_space)
fsm.add_transition('jumping', 'idle', if_grounded)
own['fsm'] = fsm
def main():
own['fsm'].main()
if 'fsm' in own:
init()
else:
main()