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.

458 lines
16KB

  1. from . import gbe
  2. import pygame
  3. class NodeInterface(gbe.nodes.NodeSurface):
  4. def __init__(self, name="Interface", parent=None):
  5. try:
  6. gbe.nodes.NodeSurface.__init__(self, name, parent)
  7. except gbe.nodes.NodeError as e:
  8. raise e
  9. def on_render(self):
  10. size = self.resolution
  11. self.draw_rect((0, 0, size[0], 10), pygame.Color(255,0,0,128), 1)
  12. self.draw_circle((int(size[0]/2), int(size[1]/2)), 16, pygame.Color(255,0,0,255), 2, pygame.Color(0,255,0,255))
  13. class NodeGameMap(gbe.nodes.Node2D):
  14. def __init__(self, name="GameMap", parent=None):
  15. try:
  16. gbe.nodes.Node2D.__init__(self, name, parent)
  17. except gbe.nodes.NodeError as e:
  18. raise e
  19. self._renderMode = 0 # 0 = Top-down | 1 = Perspective
  20. self._layer = {}
  21. self._currentLayer = ""
  22. self._res = {
  23. "env_src":"",
  24. "env":None,
  25. "wall_src":"",
  26. "walls":None,
  27. "wall_index":-1,
  28. "door_index":-1
  29. }
  30. self._topdown = {
  31. "size":8, # Pixels square
  32. "wall_color":pygame.Color(255, 255, 255),
  33. "blocked_color":pygame.Color(255, 0, 0)
  34. }
  35. self._cellpos = [0,0]
  36. self._orientation = "n"
  37. @property
  38. def environment_source(self):
  39. return self._res["env_src"]
  40. @property
  41. def wall_source(self):
  42. return self._res["wall_src"]
  43. @property
  44. def layer_count(self):
  45. return len(self._layer)
  46. @property
  47. def current_layer(self):
  48. return self._currentLayer
  49. @property
  50. def current_layer_width(self):
  51. if self._currentLayer != "":
  52. return self._layer[self._currentLayer]["w"]
  53. return 0
  54. @property
  55. def current_layer_height(self):
  56. if self._currentLayer != "":
  57. return self._layer[self._currentLayer]["h"]
  58. return 0
  59. @property
  60. def layer_names(self):
  61. names = []
  62. for key in self._layer:
  63. names.append(names)
  64. return names
  65. @property
  66. def orientation(self):
  67. return self._orientation
  68. @property
  69. def cell_position(self):
  70. return (self._cellpos[0], self._cellpos[1])
  71. def set_resources(self, env_src, wall_src):
  72. res = self.resource
  73. if env_src != "" and env_src != self._res["env_src"]:
  74. if res.is_valid("json", env_src):
  75. if not res.has("json", env_src):
  76. res.store("json", env_src)
  77. e = res.get("json", env_src)
  78. if e is not None and e() is not None:
  79. self._res["env_src"] = env_src
  80. self._res["env"] = e
  81. # NOTE: Making a lot of assumptions to the structural validity of the data file.
  82. isrc1 = e().data["horizon"]["src"]
  83. isrc2 = e().data["ground"]["src"]
  84. if res.is_valid("graphic", isrc1) and res.is_valid("graphic", isrc2):
  85. if not res.has("graphic", isrc1):
  86. res.store("graphic", isrc1)
  87. if not res.has("graphic", isrc2):
  88. res.store("graphic", isrc2)
  89. if wall_src != "" and wall_src != self._res["wall_src"]:
  90. if res.is_valid("json", wall_src):
  91. if not res.has("json", wall_src):
  92. print("Storing resource {}".format(wall_src))
  93. res.store("json", wall_src)
  94. w = res.get("json", wall_src)
  95. if w is not None and w() is not None:
  96. self._res["wall_src"] = wall_src
  97. self._res["walls"] = w
  98. # NOTE: I'm making a lot of assumptions to the structural validity of the data file, but...
  99. imgsrc = w().data["src"]
  100. if res.is_valid("graphic", imgsrc):
  101. if not res.has("graphic", imgsrc):
  102. res.store("graphic", imgsrc)
  103. else:
  104. print("Failed to get JSON instance {}".format(wall_src))
  105. else:
  106. print("Invalid JSON {}".format(wall_src))
  107. def add_layer(self, name, w, h):
  108. if name == "" or name in self._layer:
  109. return
  110. self._layer[name] = {
  111. "w":w,
  112. "h":h,
  113. "cells":[]
  114. }
  115. for c in range(0, w*h):
  116. self._layer[name]["cells"].append({
  117. "c":0, # Sky / Ceiling
  118. "g":0, # Ground
  119. "n":[-1, False, -1, None], # North Wall | [<graphic index, -1 = None>, <blocking>, <door index, -1 = None, 0 = closed, 1=open>, <door target>]
  120. "s":[-1, False, -1, None], # South Wall
  121. "e":[-1, False, -1, None], # East Wall
  122. "w":[-1, False, -1, None], # West Wall
  123. })
  124. if self._currentLayer == "":
  125. self._currentLayer = name
  126. def set_active_layer(self, name, x=0, y=0):
  127. if name == "" or not (name in self._layers):
  128. return
  129. layer = self._layers[name]
  130. if x >= 0 and x < layer["w"] and y >= 0 and y < layer["h"]:
  131. self._currentLayer = name
  132. self._cellpos = [x,y]
  133. def set_cell_env(self, x, y, ceiling=-1, ground=-1):
  134. if self._currentLayer == "":
  135. return
  136. layer = self._layer[self._currentLayer]
  137. if x >= 0 and x < layer["w"] and y >= 0 and y < layer["h"]:
  138. index = (y * layer["w"]) + x
  139. cell = layer["cells"]
  140. if ceiling >= 0:
  141. cell[index]["c"] = ceiling
  142. if ground >= 0:
  143. cell[index]["g"] = ground
  144. def fill_cell_env(self, x1, y1, x2, y2, ceiling=-1, ground=-1):
  145. if self._currentLayer == "":
  146. return
  147. for y in range(y1, y2+1):
  148. for x in range(x1, x2+1):
  149. self.set_cell_env(x, y, ceiling, ground)
  150. def set_cell_face(self, x, y, face, gi=-2, blocking=None):
  151. if self._currentLayer == "" or not (face == "n" or face == "s" or face == "w" or face == "e"):
  152. return
  153. layer = self._layer[self._currentLayer]
  154. if x >= 0 and x < layer["w"] and y >= 0 and y < layer["h"]:
  155. index = (y * layer["w"]) + x
  156. cell = layer["cells"]
  157. if gi <= -2:
  158. gi = self._res["wall_index"]
  159. if gi >= -1:
  160. cell[index][face][0] = gi
  161. if blocking is not None:
  162. cell[index][face][1] = (blocking == True)
  163. else:
  164. if gi == -1: # If gi = -1, there is no wall, so, by default, there is no blocking.
  165. cell[index][face][1] = False
  166. else: # Otherwise, blocking is assumed :)
  167. cell[index][face][1] = True
  168. elif blocking is not None:
  169. blocking = (blocking == True) # Forcing a boolean
  170. cell[index][face][1] = blocking
  171. def next_wall(self):
  172. if self._res["walls"] is not None:
  173. w = self._res["walls"]()
  174. if w is not None:
  175. windex = self._res["wall_index"] + 1
  176. if windex >= len(w.data["walls"]):
  177. windex = -1
  178. self._res["wall_index"] = windex
  179. print("Next Wall Index: {}".format(windex))
  180. def prev_wall(self):
  181. if self._res["walls"] is not None:
  182. w = self._res["walls"]()
  183. if w is not None:
  184. windex = self._res["wall_index"] - 1
  185. if windex < -1:
  186. windex = len(w.data["walls"]) - 1
  187. self._res["wall_index"] = windex
  188. print("Prev Wall Index: {}".format(windex))
  189. def turn_left(self):
  190. onum = self._d_s2n(self._orientation)
  191. onum -= 1
  192. if onum < 0:
  193. onum = 3
  194. self._orientation = self._d_n2s(onum)
  195. def turn_right(self):
  196. onum = self._d_s2n(self._orientation)
  197. onum += 1
  198. if onum > 3:
  199. onum = 0
  200. self._orientation = self._d_n2s(onum)
  201. def move_to(self, x, y):
  202. if x >= 0 and x < self.current_layer_width and y >= 0 and y < self.current_layer_height:
  203. self._cellpos = [x, y]
  204. def move_forward(self, ignore_passible=False):
  205. if ignore_passible or self.is_passible(self._cellpos[0], self._cellpos[1], self._orientation):
  206. x = self._cellpos[0]
  207. y = self._cellpos[1]
  208. if self._orientation == "n":
  209. y -= 1
  210. elif self._orientation == "e":
  211. x += 1
  212. elif self._orientation == "s":
  213. y += 1
  214. elif self._orientation == "w":
  215. x -= 1
  216. self.move_to(x, y)
  217. def move_backward(self, ignore_passible=False):
  218. orient = self._orientation
  219. if self._orientation == "n":
  220. self._orientation = "s"
  221. elif self._orientation == "s":
  222. self._orientation = "n"
  223. elif self._orientation == "e":
  224. self._orientation = "w"
  225. elif self._orientation == "w":
  226. self._orientation = "e"
  227. self.move_forward(ignore_passible)
  228. self._orientation = orient
  229. def is_passible(self, x, y, d):
  230. """
  231. Returns true if it's possible to move forward from the x, y map position in the direction given.
  232. d - 0 = North, 1 = East, 2 = South, 3 = West
  233. """
  234. if self._currentLayer == "" or d < 0 or d >= 4:
  235. return False
  236. layer = self._layer[self._currentLayer]
  237. if x >= 0 and x < layer["w"] and y >= 0 and y < layer["h"]:
  238. index = (y * layer["w"]) + x
  239. d = self._d_n2s(d)
  240. return not layer["cells"][index][d][1]
  241. return False
  242. def _d_n2s(self, d): # _(d)irection_(n)umber_to_(s)tring
  243. if d == 0:
  244. return "n"
  245. elif d == 1:
  246. return "e"
  247. elif d == 2:
  248. return "s"
  249. elif d == 3:
  250. return "w"
  251. return ""
  252. def _d_s2n(self, d):
  253. if d == "n":
  254. return 0
  255. elif d == "e":
  256. return 1
  257. elif d == "s":
  258. return 2
  259. elif d == "w":
  260. return 3
  261. return -1
  262. def _indexFromPos(self, x, y):
  263. if x >= 0 and x < self.current_layer_width and y >= 0 and y < self.current_layer_height:
  264. return (y * self.current_layer_width) + x
  265. return -1
  266. def _getCell(self, x, y):
  267. index = self._indexFromPos(x, y)
  268. if index < 0:
  269. return None
  270. return self._layer[self._currentLayer]["cells"][index]
  271. def _RenderTopDown(self):
  272. cell_size = self._topdown["size"]
  273. size = self.resolution
  274. pos = self._cellpos
  275. lsize = (self.current_layer_width, self.current_layer_height)
  276. hcells = int(size[0] / cell_size)
  277. vcells = int(size[1] / cell_size)
  278. cx = pos[0] - int(hcells * 0.5)
  279. cy = pos[1] - int(vcells * 0.5)
  280. ry = -int(cell_size*0.5)
  281. for j in range(0, vcells+1):
  282. y = cy + j
  283. if y >= 0 and y < lsize[1]:
  284. rx = -int(cell_size*0.5)
  285. for i in range(0, hcells+1):
  286. x = cx + i
  287. if x >= 0 and x < lsize[0]:
  288. cell = self._getCell(x, y)
  289. if cell["n"][0] >= 0:
  290. self.draw_rect((rx, ry, cell_size, 2), self._topdown["wall_color"], 0, self._topdown["wall_color"])
  291. if cell["e"][0] >= 0:
  292. self.draw_rect((rx+(cell_size-2), ry, 2, cell_size), self._topdown["wall_color"], 0, self._topdown["wall_color"])
  293. if cell["s"][0] >= 0:
  294. self.draw_rect((rx, ry+(cell_size-2), cell_size, 2), self._topdown["wall_color"], 0, self._topdown["wall_color"])
  295. if cell["w"][0] >= 0:
  296. self.draw_rect((rx, ry, 2, cell_size), self._topdown["wall_color"], 0, self._topdown["wall_color"])
  297. if cell["n"][1] == True:
  298. self.draw_lines([(rx+1, ry+1), (rx+(cell_size-2), ry+1)], self._topdown["blocked_color"], 1)
  299. if cell["e"][1] == True:
  300. self.draw_lines([(rx+(cell_size-2), ry+1), (rx+(cell_size-2), ry+(cell_size-2))], self._topdown["blocked_color"], 1)
  301. if cell["s"][1] == True:
  302. self.draw_lines([(rx+1, ry+(cell_size-2)), (rx+(cell_size-2), ry+(cell_size-2))], self._topdown["blocked_color"], 1)
  303. if cell["w"][1] == True:
  304. self.draw_lines([(rx+1, ry+1), (rx+1, ry+(cell_size-2))], self._topdown["blocked_color"], 1)
  305. rx += cell_size
  306. ry += cell_size
  307. def _RenderPerspective(self):
  308. pass
  309. def on_render(self):
  310. if self._renderMode == 0:
  311. self._RenderTopDown()
  312. else:
  313. self._RenderPerspective()
  314. class NodeMapEditor(gbe.nodes.Node2D):
  315. def __init__(self, name="MapEditor", parent=None):
  316. try:
  317. gbe.nodes.Node2D.__init__(self, name, parent)
  318. except gbe.nodes.Node2D as e:
  319. raise e
  320. self._last_orientation = ""
  321. self._size = 0
  322. self._thickness = 1
  323. self._color = pygame.Color(255,255,255)
  324. self._points = None
  325. self.pointer_size = 4
  326. def _getPoints(self, size):
  327. p = self.parent
  328. o = p.orientation
  329. points = self._points[o]
  330. hw = int(size[0]*0.5)
  331. hh = int(size[1]*0.5)
  332. return (
  333. (points[0][0] + hw, points[0][1] + hh),
  334. (points[1][0] + hw, points[1][1] + hh),
  335. (points[2][0] + hw, points[2][1] + hh)
  336. )
  337. @property
  338. def pointer_size(self):
  339. return self._size
  340. @pointer_size.setter
  341. def pointer_size(self, size):
  342. if not isinstance(size, int):
  343. raise TypeError("Size expected to be an integer.")
  344. if size <= 0:
  345. raise ValueError("Size must be greater than zero.")
  346. if size != self._size:
  347. self._size = size
  348. # Now updating all of the pointer... ummm... points
  349. hs = max(1, int(size * 0.5))
  350. self._points = {
  351. "n": ((0,-hs),(hs,hs),(-hs,hs)),
  352. "s": ((0,hs),(hs,-hs),(-hs,-hs)),
  353. "e": ((-hs,hs),(hs,0),(-hs,-hs)),
  354. "w": ((hs,hs),(-hs,0),(hs,-hs))
  355. }
  356. def set_color(self, color):
  357. if isinstance(color, (tuple, list)):
  358. clen = len(color)
  359. if clen == 3 or clen == 4:
  360. iscolor = lambda v : isinstance(v, int) and v >= 0 and v < 256
  361. if iscolor(color[0]) and iscolor(color[1]) and iscolor(color[2]):
  362. if clen == 3:
  363. self._color = pygame.Color(color[0], color[1], color[2])
  364. elif clen == 4 and iscolor(color[3]):
  365. self._color = pygame.Color(color[0], color[1], color[2], color[3])
  366. def get_color(self):
  367. return (self._color.r, self._color.g, self._color.b, self._color.a)
  368. def on_start(self):
  369. self.listen("KEYPRESSED", self.on_keypressed)
  370. def on_pause(self):
  371. self.unlisten("KEYPRESSED", self.on_keypressed)
  372. def on_keypressed(self, event, data):
  373. p = self.parent
  374. if p is None or not isinstance(p, NodeGameMap):
  375. return
  376. if data["key_name"] == "escape":
  377. self.emit("QUIT")
  378. if data["key_name"] == "w":
  379. p.move_forward(True)
  380. elif data["key_name"] == "s":
  381. p.move_backward(True)
  382. elif data["key_name"] == "a":
  383. p.turn_left()
  384. elif data["key_name"] == "d":
  385. p.turn_right()
  386. elif data["key_name"] == "space":
  387. o = p.orientation
  388. cpos = p.cell_position
  389. p.set_cell_face(cpos[0], cpos[1], o)
  390. elif data["key_name"] == "e":
  391. p.next_wall()
  392. elif data["key_name"] == "q":
  393. p.prev_wall()
  394. def on_render(self):
  395. size = self.resolution
  396. self.draw_lines(self._getPoints(size), self._color, self._thickness, True)