Legend of the Gold Box... A game written for the LOWREZJAM 2018 game jam
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

138 lines
3.9KB

  1. from .events import Events
  2. from .nodes import Node
  3. from .time import Time
  4. from .display import Display
  5. class StateMachineError(Exception):
  6. pass
  7. # This is the main, active state (Node).
  8. _ACTIVE_STATE = None
  9. # In some cases, the previous state isn't totally shut down, but temporarily put on hold.
  10. # Only the _render() call will be made on hold states.
  11. _HOLD_STATE = None
  12. # List of all states registered into the State Manager.
  13. _STATE_LIST = []
  14. _TIME = Time()
  15. class StateMachine:
  16. def __init__(self):
  17. Events.listen("SCENECHANGE", self.on_scenechange)
  18. def on_scenechange(self, event, params):
  19. if "scene" in params and "hold" in params:
  20. self.activate_node(params["scene"], params["hold"])
  21. def has_node(self, name):
  22. """
  23. Returns true if a Node with the given name has been registered in the State List.
  24. NOTE: This is only going to check the root Node's name, not any other node in the node tree.
  25. """
  26. global _STATE_LIST
  27. for n in _STATE_LIST:
  28. if n.name == name:
  29. return True
  30. return False
  31. def register_node(self, node):
  32. """
  33. """
  34. if not isinstance(node, Node):
  35. raise TypeError("Expected a Node instance.")
  36. # Check if given the root Node. If not, get the root Node.
  37. if node.parent != None:
  38. node = node.root
  39. if self.has_node(node.name):
  40. raise StateMachineError("State machine already registered node named '{}'. Names must be unique.".format(node.name))
  41. global _STATE_LIST
  42. _STATE_LIST.append(node)
  43. def activate_node(self, name, hold_previous=False):
  44. """
  45. """
  46. global _ACTIVE_STATE, _TIME
  47. if self.has_node(name):
  48. if _ACTIVE_STATE is not None:
  49. if _ACTIVE_STATE.name == name:
  50. return
  51. self._releaseActive(hold_previous)
  52. self._setActive(name)
  53. if _ACTIVE_STATE is not None:
  54. _TIME.reset()
  55. def _releaseActive(self, hold_previous):
  56. global _ACTIVE_STATE, _HOLD_STATE
  57. a = _ACTIVE_STATE
  58. a._pause()
  59. if _HOLD_STATE is not None:
  60. _ACTIVE_STATE = _HOLD_STATE
  61. _HOLD_STATE = None
  62. _ACTIVE_STATE._start()
  63. else:
  64. _ACTIVE_STATE = None
  65. if hold_previous == True:
  66. _HOLD_STATE = a
  67. else:
  68. a._close()
  69. def _setActive(self, name):
  70. global _ACTIVE_STATE, _STATE_LIST
  71. for n in _STATE_LIST:
  72. if n.name == name:
  73. _ACTIVE_STATE = n
  74. break
  75. if _ACTIVE_STATE is not None:
  76. _ACTIVE_STATE._init()
  77. _ACTIVE_STATE._start()
  78. elif _HOLD_STATE is not None:
  79. # If we failed to find an Active state, then we need to drop any hold state as well...
  80. # Keep things as clean as possible
  81. _HOLD_STATE._close()
  82. _HOLD_STATE = None
  83. def close(self):
  84. global _ACTIVE_STATE, _HOLD_STATE, _STATE_LIST
  85. if _HOLD_STATE is not None:
  86. _HOLD_STATE._close()
  87. _HOLD_STATE = None
  88. if _ACTIVE_STATE is not None:
  89. _ACTIVE_STATE._pause()
  90. _ACTIVE_STATE._close()
  91. _ACTIVE_STATE = None
  92. _STATE_LIST = []
  93. def update(self):
  94. global _ACTIVE_STATE, _TIME
  95. if _ACTIVE_STATE is not None:
  96. _ACTIVE_STATE._update(_TIME.delta)
  97. def render(self):
  98. global _ACTIVE_STATE, _HOLD_STATE
  99. dsurf = Display.surface
  100. if dsurf is not None:
  101. Display.clear()
  102. # If there's a hold state, render that first.
  103. if _HOLD_STATE is not None:
  104. _HOLD_STATE._render(dsurf)
  105. # Render the active state next so it overdraws the hold state.
  106. if _ACTIVE_STATE is not None:
  107. _ACTIVE_STATE._render(dsurf)
  108. Display.flip()