Legend of the Gold Box... A game written for the LOWREZJAM 2018 game jam
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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