Legend of the Gold Box... A game written for the LOWREZJAM 2018 game jam
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

362 行
11KB

  1. '''
  2. Filename nodes.py
  3. Author: Bryan "ObsidianBlk" Miller
  4. Date Created: 8/1/2018
  5. Python Version: 3.7
  6. '''
  7. from .display import Display
  8. class NodeError(Exception):
  9. pass
  10. class Node:
  11. def __init__(self, name="Node", parent=None):
  12. self._parent = None
  13. self._name = name
  14. self._children = []
  15. if parent is not None:
  16. try:
  17. self.parent = parent
  18. except NodeError as e:
  19. raise e
  20. @property
  21. def parent(self):
  22. return self._parent
  23. @parent.setter
  24. def parent(self, new_parent):
  25. try:
  26. self.parent_to_node(new_parent)
  27. except NodeError as e:
  28. raise e
  29. @property
  30. def root(self):
  31. if self._parent is None:
  32. return self
  33. return self._parent.root
  34. @property
  35. def name(self):
  36. return self._name
  37. @name.setter
  38. def name(self, value):
  39. if self._parent is not None:
  40. if self._parent.get_node(value) is not None:
  41. raise NodeError("Parent already contains node named '{}'.".format(name))
  42. self._name = value
  43. @property
  44. def full_name(self):
  45. if self._parent is None:
  46. return self._name
  47. return self._parent.full_name + "." + self._name
  48. @property
  49. def child_count(self):
  50. return len(this._children)
  51. def parent_to_node(self, parent, allow_reparenting=False):
  52. if not isinstance(value, Node):
  53. raise NodeError("Node may only parent to another Node instance.")
  54. if self._parent is None or self._parent != parent:
  55. if self._parent is not None:
  56. if allow_Reparenting == False:
  57. raise NodeError("Node already assigned a parent Node.")
  58. if self._parent.remove_node(self) != self:
  59. raise NodeError("Failed to remove self from current parent.")
  60. try:
  61. parent.attach_node(self)
  62. except NodeError as e:
  63. raise e
  64. def attach_node(self, node, reparent=False, index=-1):
  65. if node.parent is not None:
  66. if node.parent == self:
  67. return # Nothing to do. Given node already parented to this node.
  68. if reparent == False:
  69. raise NodeError("Node already parented.")
  70. if node.parent.remove_node(node) != node:
  71. raise NodeError("Failed to remove given node from it's current parent.")
  72. if self.get_node(node.name) is not None:
  73. raise NodeError("Node with name '{}' already attached.".format(node.name))
  74. node._parent = self
  75. if index < 0 or index >= len(self._children):
  76. self._children.append(node)
  77. else:
  78. self._children.insert(index, node)
  79. def remove_node(self, node):
  80. if isinstance(node, (str, unicode)):
  81. n = self.get_node(node)
  82. if n is not None:
  83. try:
  84. return self.remove_node(n)
  85. except NodeError as e:
  86. raise e
  87. elif isinstance(node, Node):
  88. if node.parent != self:
  89. if node.parent == None:
  90. raise NodeError("Cannot remove an unparented node.")
  91. try:
  92. return node.parent.remove_node(node)
  93. except NodeError as e:
  94. raise e
  95. if node in self._children:
  96. self._children.remove(node)
  97. node._parent = None
  98. return node
  99. else:
  100. raise NodeError("Expected a Node instance or a string.")
  101. return None
  102. def get_node(self, name):
  103. if len(self._children) <= 0:
  104. return None
  105. subnames = name.split(".")
  106. for c in self._children:
  107. if c.name == subnames[0]:
  108. if len(subnames) > 1:
  109. return c.get_node(".".join(subnames[1:-1]))
  110. return c
  111. return None
  112. def _update(self, dt):
  113. if hasattr(self, "on_update"):
  114. self.on_update(dt)
  115. for c in self._children:
  116. c._update(dt)
  117. def _render(self, surface):
  118. for c in self._children:
  119. c._render(surface)
  120. class Node2D(Node):
  121. def __init__(self, name="Node2D", parent=None):
  122. try:
  123. Node.__init__(self, name, parent)
  124. except NodeError as e:
  125. raise e
  126. def _render(self, surface):
  127. Node._render(self, surface)
  128. if hasattr(self, "on_render"):
  129. self._ACTIVE_SURF = surface
  130. self.on_render()
  131. del self._ACTIVE_SURF
  132. def blit(self, img, pos=(0,0), rect=None):
  133. if not hasattr(self, "_ACTIVE_SURF"):
  134. return
  135. self._ACTIVE_SURF.blit(img, pos, rect)
  136. def fill(self, color):
  137. if not hasattr(self, "_ACTIVE_SURF"):
  138. return
  139. self._ACTIVE_SURF.fill(color)
  140. def draw_lines(points, color, thickness=1, closed=False):
  141. if not hasattr(self, "_ACTIVE_SURF"):
  142. return
  143. pygame.draw.lines(self._ACTIVE_SURF, color, closed, points, thickness)
  144. def draw_rect(rect, color, thinkness=1):
  145. if not hasattr(self, "_ACTIVE_SURF"):
  146. return
  147. pygame.draw.rect(self._ACTIVE_SURF, color, rect, thickness)
  148. def draw_ellipse(rect, color, thickness=1, fill_color=None):
  149. if not hasattr(self, "_ACTIVE_SURF"):
  150. return
  151. if fill_color is not None:
  152. pygame.draw.ellipse(self._ACTIVE_SURF, fill_color, rect)
  153. if thickness > 0:
  154. pygame.draw.ellipse(self._ACTIVE_SURF, color, rect, thickness)
  155. def draw_circle(pos, radius, color, thickness=1, fill_color=None):
  156. if not hasattr(self, "_ACTIVE_SURF"):
  157. return
  158. if fill_color is not None:
  159. pygame.draw.circle(self._ACTIVE_SURF, fill_color, pos, radius)
  160. if thickness > 0:
  161. pygame.draw.circle(self._ACTIVE_SURF, color, pos, radius, thickness)
  162. def draw_polygon(points, color, thickness=1, fill_color=None):
  163. if not hasattr(self, "_ACTIVE_SURF"):
  164. return
  165. if fill_color is not None:
  166. pygame.draw.polygon(self._ACTIVE_SURF, fill_color, points)
  167. if thickness >= 1:
  168. pygame.draw.polygon(self._ACTIVE_SURF, color, points, thickness)
  169. class NodeSurface(Node2D):
  170. def __init__(self, name="NodeSurface", parent=None):
  171. try:
  172. Node2D.__init__(self, name, parent)
  173. except NodeError as e:
  174. raise e
  175. self._offset = (0.0, 0.0)
  176. self._scale = (1.0, 1.0)
  177. self._keepAspectRatio = False
  178. self._surface = None
  179. self._tsurface = None
  180. self.set_surface()
  181. def _updateTransformSurface(self):
  182. if self._surface is None:
  183. return
  184. if self._scale[0] == 1.0 and self._scale[1] == 1.0:
  185. self._tsurface = None
  186. size = self._surface.get_size()
  187. nw = size[0] * self._scale[0]
  188. nh = 0
  189. if self._keepAspectRatio:
  190. nh = size[1] * self._scale[0]
  191. else:
  192. nh = size[1] * self._scale[1]
  193. self._tsurface = pygame.Surface((nw, nh), pygame.SRCALPHA, self._surface)
  194. @property
  195. def resolution(self):
  196. if self._surface is None:
  197. return (0,0)
  198. return self._surface.get_size()
  199. @resolution.setter
  200. def resolution(self, res):
  201. try:
  202. self.set_surface(res)
  203. except (TypeError, ValueError) as e:
  204. raise e
  205. @property
  206. def width(self):
  207. return self.resolution[0]
  208. @property
  209. def height(self):
  210. return self.resolution[1]
  211. @property
  212. def offset(self):
  213. return self._offset
  214. @offset.setter(self, offset):
  215. if not isinstance(offset, tuple):
  216. raise TypeError("Expected a tuple")
  217. if len(offset) != 2:
  218. raise ValueError("Expected tuple of length two.")
  219. if not isinstance(offset[0], (int, float)) or not isinstance(offset[1], (int, float)):
  220. raise TypeError("Expected number values.")
  221. self._offset = (float(offset[0]), float(offset[1]))
  222. @property
  223. def offset_x(self):
  224. return self._offset[0]
  225. @offset_x.setter
  226. def offset_x(self, x):
  227. if not isinstance(x, (int, float)):
  228. raise TypeError("Expected number value.")
  229. self._offset = (x, self._offset[1])
  230. @property
  231. def offset_y(self):
  232. return self._offset[1]
  233. @offset_y.setter
  234. def offset_y(self, y):
  235. if not isinstance(y, (int, float)):
  236. raise TypeError("Expected number value.")
  237. self._offset = (self._offset[0], y)
  238. @property
  239. def scale(self):
  240. return self._scale
  241. @scale.setter
  242. def scale(self, scale):
  243. if self._keepAspectRatio:
  244. if not isinstance(scale, (int, float)):
  245. raise TypeError("Expected number value.")
  246. self._scale = (scale, self._scale[1])
  247. else:
  248. if not isinstance(scale, tuple):
  249. raise TypeError("Expected a tuple")
  250. if len(scale) != 2:
  251. raise ValueError("Expected tuple of length two.")
  252. if not isinstance(scale[0], (int, float)) or not isinstance(scale[1], (int, float)):
  253. raise TypeError("Expected number values.")
  254. self._scale = scale
  255. self._updateTransformSurface()
  256. @property
  257. def keep_aspect_ratio(self):
  258. return self._keepAspectRatio
  259. @keep_aspect_ratio.setter
  260. def keep_aspect_ratio(self, keep):
  261. self._keepAspectRatio = (keep == True)
  262. self._updateTransformSurface()
  263. def scale_to(self, target_resolution):
  264. if self._surface is not None:
  265. size = self._surface.get_size()
  266. nscale = (float(size[0]) / float(target_resolution[0]), float(size[1]) / float(target_resolution[1]))
  267. self.scale = nscale
  268. def set_surface(self, resolution=None):
  269. dsurf = Display.surface
  270. if resolution is None:
  271. if dsurf is not None:
  272. self._surface = dsurf.convert_alpha()
  273. self._updateTransformSurface()
  274. else:
  275. if not isinstance(r, tuple):
  276. raise TypeError("Expected a tuple.")
  277. if len(r) != 2:
  278. raise ValueError("Expected a tuple of length two.")
  279. if not isinstance(r[0], int) or not isinstance(r[1], int):
  280. raise TypeError("Tuple expected to contain integers.")
  281. if dsurf is not None:
  282. self._surface = pygame.Surface(resolution, pygame.SRCALPHA, dsurf)
  283. else:
  284. self._surface = pygame.Surface(resolution, pygame.SRCALPHA)
  285. self._updateTransformSurface()
  286. def _render(self, surface):
  287. if self._surface is None:
  288. self.set_surface()
  289. if self._surface is not None:
  290. Node2D._render(self, self._surface)
  291. else:
  292. Node2D._render(self, surface)
  293. self._scale_and_blit(surface)
  294. def _scale_and_blit(self, dest):
  295. dsize = dest.get_size()
  296. pos = (int(self._offset[0]), int(self._offset[1]))
  297. src = self._surface
  298. if self._tsurface is not None:
  299. pygame.transform.scale(self._surface, self._tsurface.get_size(), self._tsurface)
  300. src = self._tsurface
  301. if ssize[0] == dsize[0] and ssize[1] == dsize[1]:
  302. dest.blit(src, pos)