DungeonGenerator.lua 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. local Bresenham = require("bresenham/bresenham")
  2. local Delaunay = require("delaunay/delaunay")
  3. local Point = Delaunay.Point
  4. local Map = require("Map")
  5. local Room = require("Room")
  6. local Node = require("Graph/Node")
  7. local Graph = require("Graph/Graph")
  8. local MST = require("Graph/MST")
  9. require("func")
  10. local Generator = {
  11. _VERSION = "0",
  12. DIMENSION=64,
  13. NB_ROOMS = 400
  14. }
  15. function roundm(n, m) return math.floor(((n + m - 1)/m))*m end
  16. function getRandomPointInCircle(radius)
  17. local t = 2*math.pi*math.random()
  18. local u = math.random()+math.random()
  19. local r = nil
  20. if u > 1 then r = 2-u else r = u end
  21. return radius*r*math.cos(t), radius*r*math.sin(t)
  22. end
  23. function trim_table(t, indices)
  24. function reverse(tbl)
  25. local r = {}
  26. for i=1, math.floor(#tbl / 2) do
  27. r[i], r[#tbl - i + 1] = tbl[#tbl - i + 1], tbl[i]
  28. end
  29. return r
  30. end
  31. -- We're reversing the indcies to avoid removing the wrong rooms by popping the items.
  32. for _,i in pairs(reverse(indices)) do
  33. table.remove(t, i)
  34. end
  35. end
  36. -- Dirty and unoptimized room generation
  37. function generate_rooms()
  38. local rooms = {}
  39. for i=1, Generator.NB_ROOMS do
  40. width,height = roundm(math.pow(math.random(), 2)*10+2,1), roundm(math.pow(math.random(), 2)*10+2,1)
  41. local x,y= getRandomPointInCircle(16-math.max(width, height))
  42. x = x+Generator.DIMENSION/2
  43. y = y+Generator.DIMENSION/2
  44. local r = Room(x, y, width, height)
  45. table.insert(rooms, r)
  46. end
  47. local done = false
  48. local pass = 0
  49. while not done do
  50. -- Repulsion calculation
  51. for a_i, a in pairs(rooms) do
  52. a.vx, a.vy = 0,0
  53. for b_i, b in pairs(rooms) do
  54. if (a_i ~= b_i) and a:intersects(b) then
  55. local dx = a.x - b.x
  56. local dy = a.y - b.y
  57. local l = math.sqrt(dx*dx + dy*dy)
  58. a.vx = a.vx + dx/l
  59. a.vy = a.vy + dy/l
  60. break
  61. end
  62. end
  63. end
  64. -- Repulsion applicaiton and room carving
  65. for _, room in pairs(rooms) do
  66. local l = math.sqrt(room.vx*room.vx + room.vy*room.vy)
  67. if l >= 0.01 then
  68. room.x = room.x + room.vx/l
  69. room.y = room.y + room.vy/l
  70. end
  71. end
  72. -- triming out of bounds rooms
  73. for i=#rooms,1,-1 do
  74. local room = rooms[i]
  75. if room.x < 1 or room.y < 1 or room.x >= Generator.DIMENSION-room.width-1 or room.y >= Generator.DIMENSION-room.height-1 then
  76. table.remove(rooms, i)
  77. end
  78. end
  79. -- Exit check
  80. done = true
  81. for a_i, a in pairs(rooms) do
  82. for b_i, b in pairs(rooms) do
  83. if a_i ~= b_i and a:intersects(b) then
  84. done = false
  85. break
  86. end
  87. end
  88. if not done then break end
  89. end
  90. pass = pass+1
  91. end
  92. return rooms
  93. end
  94. function Generator.generate(seed)
  95. math.randomseed(seed)
  96. local rooms = generate_rooms()
  97. -- Keeping the biggest rooms
  98. local biggest_rooms = filter(function(r) return r.width >= 4 and r.height >= 4 end, rooms)
  99. -- Generating their centers
  100. local centers = map(function(r) return Point(r.x+r.width/2, r.y+r.height/2) end, biggest_rooms)
  101. local triangles = Delaunay.triangulate(unpack(centers))
  102. local edges = {}
  103. for i, triangle in ipairs(triangles) do
  104. for _,edge in pairs({triangle.e1, triangle.e2, triangle.e3}) do
  105. local found = false
  106. for _,v in pairs(edges) do
  107. if v == edge then
  108. found = true
  109. break
  110. end
  111. end
  112. if not found then
  113. table.insert(edges, edge)
  114. end
  115. end
  116. end
  117. local graph = Graph(centers, edges)
  118. local res = graph
  119. if #edges > 3 then
  120. res = MST.search(graph,
  121. function(edge)
  122. local dx = edge.p1.x - edge.p2.x
  123. local dy = edge.p1.y - edge.p2.y
  124. return math.sqrt(dx*dx+dy*dy)
  125. end
  126. )
  127. end
  128. local m = Map(Generator.DIMENSION, Generator.DIMENSION)
  129. for _, r in pairs(biggest_rooms) do
  130. m:carve(r)
  131. end
  132. for _,edge in pairs(res.edges) do
  133. local vertices_ok = 0
  134. for _,c in pairs(centers) do
  135. if edge.p1.id ==c.id or edge.p2.id == c.id then
  136. vertices_ok = vertices_ok + 1
  137. end
  138. end
  139. if vertices_ok == 2 then
  140. Bresenham.los(math.floor(edge.p1.x), math.floor(edge.p1.y), math.floor(edge.p2.x), math.floor(edge.p2.y),
  141. function(x, y)
  142. m.tiles[y][x] = 0
  143. return true
  144. end
  145. )
  146. end
  147. end
  148. return m
  149. end
  150. return Generator