state_machine.gd 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. extends 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. signal state_changed(current_state)
  8. # You should set a starting node from the inspector or on the node that inherits
  9. # from this state machine interface. If you don't, the game will default to
  10. # the first state in the state machine's children.
  11. @export var start_state: NodePath
  12. var states_map = {}
  13. var states_stack = []
  14. var current_state = null
  15. var _active = false:
  16. set(value):
  17. _active = value
  18. set_active(value)
  19. func _enter_tree():
  20. if start_state.is_empty():
  21. start_state = get_child(0).get_path()
  22. for child in get_children():
  23. var err = child.finished.connect(self._change_state)
  24. if err:
  25. printerr(err)
  26. initialize(start_state)
  27. func initialize(initial_state):
  28. _active = true
  29. states_stack.push_front(get_node(initial_state))
  30. current_state = states_stack[0]
  31. current_state.enter()
  32. func set_active(value):
  33. set_physics_process(value)
  34. set_process_input(value)
  35. if not _active:
  36. states_stack = []
  37. current_state = null
  38. func _unhandled_input(event):
  39. current_state.handle_input(event)
  40. func _physics_process(delta):
  41. current_state.update(delta)
  42. func _on_animation_finished(anim_name):
  43. if not _active:
  44. return
  45. current_state._on_animation_finished(anim_name)
  46. func _change_state(state_name):
  47. if not _active:
  48. return
  49. current_state.exit()
  50. if state_name == "previous":
  51. states_stack.pop_front()
  52. else:
  53. states_stack[0] = states_map[state_name]
  54. current_state = states_stack[0]
  55. emit_signal("state_changed", current_state)
  56. if state_name != "previous":
  57. current_state.enter()