1extends Node 2# Base interface for a generic state machine. 3# It handles initializing, setting the machine active or not 4# delegating _physics_process, _input calls to the State nodes, 5# and changing the current/active state. 6# See the PlayerV2 scene for an example on how to use it. 7 8signal state_changed(current_state) 9 10# You should set a starting node from the inspector or on the node that inherits 11# from this state machine interface. If you don't, the game will default to 12# the first state in the state machine's children. 13export(NodePath) var start_state 14var states_map = {} 15 16var states_stack = [] 17var current_state = null 18var _active = false setget set_active 19 20func _ready(): 21 if not start_state: 22 start_state = get_child(0).get_path() 23 for child in get_children(): 24 var err = child.connect("finished", self, "_change_state") 25 if err: 26 printerr(err) 27 initialize(start_state) 28 29 30func initialize(initial_state): 31 set_active(true) 32 states_stack.push_front(get_node(initial_state)) 33 current_state = states_stack[0] 34 current_state.enter() 35 36 37func set_active(value): 38 _active = value 39 set_physics_process(value) 40 set_process_input(value) 41 if not _active: 42 states_stack = [] 43 current_state = null 44 45 46func _unhandled_input(event): 47 current_state.handle_input(event) 48 49 50func _physics_process(delta): 51 current_state.update(delta) 52 53 54func _on_animation_finished(anim_name): 55 if not _active: 56 return 57 current_state._on_animation_finished(anim_name) 58 59 60func _change_state(state_name): 61 if not _active: 62 return 63 current_state.exit() 64 65 if state_name == "previous": 66 states_stack.pop_front() 67 else: 68 states_stack[0] = states_map[state_name] 69 70 current_state = states_stack[0] 71 emit_signal("state_changed", current_state) 72 73 if state_name != "previous": 74 current_state.enter() 75