Advertisement
Guest User

Untitled

a guest
Sep 15th, 2019
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.43 KB | None | 0 0
  1. extends Node2D
  2.  
  3. export var scale2D = 2
  4. export var room_margin = 2
  5. export(int, 3, 13) var number_of_rooms = 5
  6. export var number_of_keys = 1
  7. export var map_width = 80
  8. export var map_height = 50
  9. export var min_room_width = 8
  10. export var max_room_width = 10
  11. export var min_room_height = 5
  12. export var max_room_height = 6
  13. export var map_seed = 2
  14.  
  15. signal graph_gen_finnished
  16.  
  17. enum eTilesType { Empty = -1, Door = 0, Wall = 1, Key = 2 }
  18.  
  19. var rooms_areas = Dictionary()
  20. var starting_room = null
  21. var ending_room = null
  22. var pathfinding := AStar.new()
  23. var rnd = RandomNumberGenerator.new()
  24.  
  25. var label = Label.new()
  26. var f = label.get_font("")
  27.  
  28. func _ready():
  29. rnd.seed = map_seed
  30. gen_graph()
  31.  
  32. func _input(event):
  33. if event is InputEventKey and not event.is_pressed() and event.scancode == KEY_SPACE:
  34. gen_graph()
  35.  
  36. func gen_graph():
  37. rooms_areas.clear()
  38. pathfinding = null
  39. rooms_areas = generate_rooms()
  40. pathfinding = generate_graph(rooms_areas.keys())
  41. update()
  42. emit_signal("graph_gen_finnished")
  43.  
  44. func generate_rooms() -> Dictionary:
  45. var rooms = Dictionary()
  46. for i in range(number_of_rooms):
  47. var room
  48. var collide = true
  49. while (collide):
  50. collide = false
  51. room = create_room()
  52. for other in rooms.values():
  53. if room.intersects(other):
  54. collide = true
  55.  
  56. if not collide:
  57. rooms[get_middle(room)] = room
  58. return rooms
  59.  
  60. func create_room() -> Rect2:
  61. var width = (2 * room_margin + min_room_width + rnd.randi() % (max_room_width + 1 - min_room_width))
  62. var height = (2 * room_margin + min_room_height + rnd.randi() % (max_room_height + 1 - min_room_height))
  63. var x = rnd.randi() % (map_width - width)
  64. var y = rnd.randi() % (map_height - height)
  65. var pos = Vector2(floor(x), floor(y))
  66. var size = Vector2(width, height)
  67. return Rect2(pos, size)
  68.  
  69. func get_room_rectangle(area: Rect2) -> Rect2:
  70. return area.grow(- room_margin)
  71.  
  72. func generate_graph(locations: Array) -> AStar:
  73. var astar = AStar.new()
  74. astar.add_point(astar.get_available_point_id(), locations.pop_front())
  75. while locations:
  76. var current_position
  77. var closest_position
  78. var min_distance = INF
  79.  
  80. for point in astar.get_points():
  81. var pos = astar.get_point_position(point)
  82. for otherPos in locations:
  83. var dist = pos.distance_to(otherPos)
  84. if dist < min_distance:
  85. min_distance = dist
  86. current_position = pos
  87. closest_position = otherPos
  88.  
  89. var point = astar.get_available_point_id()
  90. astar.add_point(point, closest_position)
  91. astar.connect_points(astar.get_closest_point(current_position), point)
  92. locations.erase(closest_position)
  93. return astar
  94.  
  95. func get_distantest_rooms() -> Array:
  96. var result = Array()
  97. var a1 = null
  98. var a2 = null
  99. var distanceMax = 0
  100. var roomsBetweenMax = 0
  101. for area in rooms_areas.values():
  102. var middleArea = get_middle(area)
  103. var pointArea = pathfinding.get_closest_point(middleArea)
  104. for other in rooms_areas.values():
  105. if area != other:
  106. var middleOther = get_middle(other)
  107. var pointOther = pathfinding.get_closest_point(middleOther)
  108. var path = pathfinding.get_id_path(pointArea, pointOther)
  109. var roomsBetween = path.size()
  110. var isDistantest = false
  111. var distance = middleArea.distance_to(middleOther)
  112. if roomsBetween > roomsBetweenMax:
  113. roomsBetweenMax = roomsBetween
  114. isDistantest = true
  115. elif roomsBetween == roomsBetweenMax:
  116. if distance > distanceMax:
  117. isDistantest = true
  118.  
  119. if isDistantest:
  120. a1 = area
  121. a2 = other
  122. distanceMax = distance
  123.  
  124. result.append(a1)
  125. result.append(a2)
  126. return result
  127.  
  128. func generate_grid_map(map:GridMap):
  129. map.clear()
  130. fill_the_map(map)
  131. write_rooms_on_map(map)
  132. write_corridors_on_map(map)
  133. var distantest = get_distantest_rooms()
  134. starting_room = distantest[0]
  135. ending_room = distantest[1]
  136. for a in distantest:
  137. var v = get_middle(a)
  138. apply_tile_on_tilemap(map, v, eTilesType.Key)
  139.  
  140.  
  141. func fill_the_map(map: GridMap):
  142. for x in range(map_width):
  143. for y in range(map_height):
  144. var v = Vector3(x, y, 0)
  145. apply_tile_on_tilemap(map, v, eTilesType.Wall)
  146.  
  147.  
  148. func write_rooms_on_map(map: GridMap):
  149. for area in rooms_areas.values():
  150. var room = get_room_rectangle(area)
  151. var left = room.position.x
  152. var right = left + room.size.x
  153. var top = room.position.y
  154. var bottom = top + room.size.y
  155. var z = 0
  156. for x in range(left, right):
  157. for y in range(top, bottom):
  158. var v = Vector3(x, y, z)
  159. apply_tile_on_tilemap(map, v, eTilesType.Empty)
  160.  
  161.  
  162. func write_corridors_on_map(map: GridMap):
  163. var rooms_done = []
  164.  
  165. for point in pathfinding.get_points():
  166. for connection in pathfinding.get_point_connections(point):
  167. if not connection in rooms_done:
  168. var posRoom1 = pathfinding.get_point_position(point)
  169. var posRoom2 = pathfinding.get_point_position(connection)
  170. var start = get_door_location(get_room_rectangle(rooms_areas[posRoom1]), posRoom2)
  171. var end = get_door_location(get_room_rectangle(rooms_areas[posRoom2]), posRoom1)
  172. dig_path(map, start, end, true, true)
  173.  
  174. rooms_done.append(point)
  175.  
  176. func dig_path(map: GridMap, start: Dictionary, end: Dictionary, doorOnStart: bool = false, doorOnEnd: bool = false):
  177. var startDir = start.keys()[0]
  178. var endDir = end.keys()[0]
  179. var startPos = to_vector3(start.values()[0])
  180. var endPos = to_vector3(end.values()[0])
  181.  
  182. var startPoint = pathfinding.get_closest_point(startPos)
  183. var endPoint = pathfinding.get_closest_point(endPos)
  184.  
  185. var horizontalStart = (startDir == "left" || startDir == "right")
  186. var horizontalEnd = (endDir == "left" || endDir == "right")
  187. var verticalStart = (startDir == "top" || startDir == "bottom")
  188. var verticalEnd = (endDir == "top" || endDir == "bottom")
  189. var horizontalPath = (horizontalStart && horizontalEnd)
  190. var verticalPath = (verticalStart && verticalEnd)
  191.  
  192. print(str(startPoint) + " -> " + str(endPoint) + " = " + str(start) + " -> " + str(end))
  193.  
  194. if horizontalPath:
  195. dig_horizontally(map, startPos, endPos, doorOnStart, doorOnEnd)
  196. elif verticalPath:
  197. dig_vertically(map, startPos, endPos, doorOnStart, doorOnEnd)
  198. else: # mixed directions
  199. if horizontalStart && verticalEnd:
  200. dig_mixed_directions(map, startPos, endPos, doorOnStart, doorOnEnd)
  201. elif verticalStart && horizontalEnd:
  202. dig_mixed_directions(map, endPos, startPos, doorOnEnd, doorOnStart)
  203.  
  204.  
  205. func dig_horizontally(map: GridMap, startPos: Vector3, endPos: Vector3, doorOnStart: bool, doorOnEnd: bool):
  206. var dif = (endPos - startPos)
  207. startPos = vector3_floor(startPos)
  208. endPos = vector3_floor(endPos)
  209. var middlePos = vector3_round(startPos + (dif / 2))
  210. var step = Vector2(sign(dif.x), sign(dif.y))
  211.  
  212. print("step " + str(step) + " dif " + str(dif))
  213. for x in range(startPos.x, endPos.x, step.x):
  214. var v : Vector3
  215. if x < middlePos.x && step.x > 0 || x > middlePos.x && step.x < 0:
  216. v = Vector3(x, startPos.y, 0)
  217. else:
  218. v = Vector3(x, endPos.y, 0)
  219. if doorOnStart && x == startPos.x + step.x ||doorOnEnd && x == endPos.x - step.x:
  220. print("door at " + str(v))
  221. apply_tile_on_tilemap(map, v, eTilesType.Door)
  222. else:
  223. apply_tile_on_tilemap(map, v, eTilesType.Empty)
  224.  
  225. for y in range(startPos.y, endPos.y, step.y):
  226. var v = Vector3(middlePos.x, y, 0)
  227. apply_tile_on_tilemap(map, v, eTilesType.Empty)
  228.  
  229.  
  230. func dig_vertically(map: GridMap, startPos: Vector3, endPos: Vector3, doorOnStart: bool, doorOnEnd: bool):
  231. var dif = (endPos - startPos)
  232. startPos = vector3_floor(startPos)
  233. endPos = vector3_floor(endPos)
  234. var middlePos = vector3_round(startPos + (dif / 2))
  235. var step = Vector2(sign(dif.x), sign(dif.y))
  236.  
  237. print("step " + str(step) + " dif " + str(dif))
  238. for y in range(startPos.y, endPos.y, step.y):
  239. var v : Vector3
  240. if y < middlePos.y && step.y > 0 || y > middlePos.y && step.y < 0:
  241. v = Vector3(startPos.x, y, 0)
  242. else:
  243. v = Vector3(endPos.x, y, 0)
  244. if doorOnStart && y == startPos.y + step.y || doorOnEnd && y == endPos.y - step.y:
  245. print("door at " + str(v))
  246. apply_tile_on_tilemap(map, v, eTilesType.Door)
  247. else:
  248. apply_tile_on_tilemap(map, v, eTilesType.Empty)
  249.  
  250. for x in range(startPos.x, endPos.x, step.x):
  251. var v = Vector3(x, middlePos.y, 0)
  252. apply_tile_on_tilemap(map, v, eTilesType.Empty)
  253.  
  254.  
  255. func dig_mixed_directions(map: GridMap, horizontalPos: Vector3, verticalPos: Vector3, doorOnHorizontal: bool, doorOnVertical: bool):
  256. var dif = (verticalPos - horizontalPos)
  257. horizontalPos = vector3_floor(horizontalPos)
  258. verticalPos = vector3_floor(verticalPos)
  259. var step = Vector2(sign(dif.x), sign(dif.y))
  260.  
  261. for x in range(horizontalPos.x, verticalPos.x, step.x):
  262. var v = Vector3(x, horizontalPos.y, 0)
  263. if doorOnHorizontal && x == horizontalPos.x + step.x:
  264. print("door at " + str(v))
  265. apply_tile_on_tilemap(map, v, eTilesType.Door)
  266. else:
  267. apply_tile_on_tilemap(map, v, eTilesType.Empty)
  268.  
  269. for y in range(horizontalPos.y, verticalPos.y, step.y):
  270. var v = Vector3(verticalPos.x, y, 0)
  271. if doorOnVertical && y == verticalPos.y - step.y:
  272. print("door at " + str(v))
  273. apply_tile_on_tilemap(map, v, eTilesType.Door)
  274. else:
  275. apply_tile_on_tilemap(map, v, eTilesType.Empty)
  276.  
  277.  
  278. func get_door_location(rect: Rect2, point: Vector3) -> Dictionary:
  279. var middle = to_vector2(get_middle(rect))
  280. var point2D = to_vector2(point)
  281. var topRight = rect.position + (rect.size * Vector2.RIGHT)
  282. var bottomLeft = rect.position + (rect.size * Vector2.DOWN)
  283. var bottomRight = rect.position + rect.size
  284. var dir = (point2D - middle).normalized()
  285. var intersections = Dictionary()
  286. intersections["top"] = (get_line_intersection(rect.position, topRight, middle, point2D) - dir)
  287. intersections["right"] = (get_line_intersection(topRight, bottomRight, middle, point2D) - dir)
  288. intersections["bottom"] = (get_line_intersection(bottomLeft, bottomRight, middle, point2D) - dir)
  289. intersections["left"] = (get_line_intersection(rect.position, bottomLeft, middle, point2D) - dir)
  290. for direction in intersections.keys():
  291. var intersection = intersections[direction]
  292. if intersection == Vector2.INF:
  293. intersections.erase(direction)
  294. return intersections
  295.  
  296.  
  297. func get_line_intersection(p1: Vector2, p2: Vector2, p3: Vector2, p4: Vector2) -> Vector2:
  298. var denominator = (p1.x - p2.x) * (p3.y - p4.y) - (p1.y - p2.y) * (p3.x - p4.x)
  299. if denominator != 0:
  300. var t = ((p1.x - p3.x) * (p3.y - p4.y) - (p1.y - p3.y) * (p3.x - p4.x)) / denominator
  301. var u = -((p1.x - p2.x) * (p1.y - p3.y) - (p1.y - p2.y) * (p1.x - p3.x)) / denominator
  302. if (t >= 0 && t <= 1 && u >= 0 && u <= 1):
  303. return Vector2(p1.x + t * (p2.x - p1.x), p1.y + t * (p2.y - p1.y));
  304. return Vector2.INF
  305.  
  306.  
  307. func apply_tile_on_tilemap(map: GridMap, pos: Vector3, tileType: int):
  308. map.set_cell_item(pos.x, pos.y, pos.z, tileType)
  309.  
  310. func to_vector3(v: Vector2, z :int = 0) -> Vector3:
  311. return Vector3(v.x, v.y, z)
  312.  
  313. func vector3_ceil(v: Vector3) -> Vector3:
  314. return Vector3(ceil(v.x), ceil(v.y), ceil(v.z))
  315.  
  316. func vector3_floor(v: Vector3) -> Vector3:
  317. return Vector3(floor(v.x), floor(v.y), floor(v.z))
  318.  
  319. func vector3_round(v: Vector3) -> Vector3:
  320. return Vector3(round(v.x), round(v.y), round(v.z))
  321.  
  322. func to_vector2(v: Vector3) -> Vector2:
  323. return Vector2(v.x, v.y)
  324.  
  325. func reverse_y_axis(v: Vector2):
  326. return Vector2(v.x, map_height - v.y)
  327.  
  328. func get_middle(r: Rect2) -> Vector3:
  329. return to_vector3(r.position + (r.size * 0.5))
  330.  
  331. func scale_rectangle(r: Rect2, scale: int, reverseY: bool = false) -> Rect2:
  332. if reverseY:
  333. var pos = Vector2(r.position.x, r.position.y + r.size.y - map_height / 2)
  334. return Rect2(reverse_y_axis(pos * scale), r.size * scale)
  335. else:
  336. return Rect2(r.position * scale, r.size * scale)
  337.  
  338. func _draw():
  339. for area in rooms_areas.values():
  340. var rect = scale_rectangle(area, scale2D, true)
  341. var pos = get_middle(rect)
  342. var point = pathfinding.get_closest_point(get_middle(area))
  343. draw_string(f, to_vector2(pos * 6), str(point), Color.red)
  344. draw_rect(rect, Color.white, false) # draw area
  345. var color = Color.blue
  346. if area == starting_room:
  347. color = Color.green
  348. elif area == ending_room:
  349. color = Color.red
  350. draw_rect(scale_rectangle(get_room_rectangle(area), scale2D, true), color, false) # draw room (without margin)
  351. draw_path(pathfinding)
  352.  
  353. func draw_path(path: AStar):
  354. if path:
  355. for point in path.get_points():
  356. for edges in path.get_point_connections(point):
  357. var pointPosition = path.get_point_position(point)
  358. var edgePosition = path.get_point_position(edges)
  359. draw_line(reverse_y_axis(to_vector2(pointPosition)) * scale2D, reverse_y_axis(to_vector2(edgePosition)) * scale2D, Color.yellow)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement