Legend of the Gold Box... A game written for the LOWREZJAM 2018 game jam
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 satır
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()