| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- local Bresenham = require("bresenham/bresenham")
- local Delaunay = require("delaunay/delaunay")
- local Point = Delaunay.Point
- local Map = require("Map")
- local Room = require("Room")
- local Node = require("Graph/Node")
- local Graph = require("Graph/Graph")
- local MST = require("Graph/MST")
- require("func")
- local Generator = {
- _VERSION = "0",
- DIMENSION=64,
- NB_ROOMS = 400
- }
- function roundm(n, m) return math.floor(((n + m - 1)/m))*m end
- function getRandomPointInCircle(radius)
- local t = 2*math.pi*math.random()
- local u = math.random()+math.random()
- local r = nil
- if u > 1 then r = 2-u else r = u end
- return radius*r*math.cos(t), radius*r*math.sin(t)
- end
- function trim_table(t, indices)
- function reverse(tbl)
- local r = {}
- for i=1, math.floor(#tbl / 2) do
- r[i], r[#tbl - i + 1] = tbl[#tbl - i + 1], tbl[i]
- end
- return r
- end
- -- We're reversing the indcies to avoid removing the wrong rooms by popping the items.
- for _,i in pairs(reverse(indices)) do
- table.remove(t, i)
- end
- end
- -- Dirty and unoptimized room generation
- function generate_rooms()
- local rooms = {}
- for i=1, Generator.NB_ROOMS do
- width,height = roundm(math.pow(math.random(), 2)*10+2,1), roundm(math.pow(math.random(), 2)*10+2,1)
- local x,y= getRandomPointInCircle(16-math.max(width, height))
- x = x+Generator.DIMENSION/2
- y = y+Generator.DIMENSION/2
- local r = Room(x, y, width, height)
- table.insert(rooms, r)
- end
- local done = false
- local pass = 0
- while not done do
- -- Repulsion calculation
- for a_i, a in pairs(rooms) do
- a.vx, a.vy = 0,0
- for b_i, b in pairs(rooms) do
- if (a_i ~= b_i) and a:intersects(b) then
- local dx = a.x - b.x
- local dy = a.y - b.y
- local l = math.sqrt(dx*dx + dy*dy)
- a.vx = a.vx + dx/l
- a.vy = a.vy + dy/l
- break
- end
- end
- end
- -- Repulsion applicaiton and room carving
- for _, room in pairs(rooms) do
- local l = math.sqrt(room.vx*room.vx + room.vy*room.vy)
- if l >= 0.01 then
- room.x = room.x + room.vx/l
- room.y = room.y + room.vy/l
- end
- end
- -- triming out of bounds rooms
- for i=#rooms,1,-1 do
- local room = rooms[i]
- 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
- table.remove(rooms, i)
- end
- end
- -- Exit check
- done = true
- for a_i, a in pairs(rooms) do
- for b_i, b in pairs(rooms) do
- if a_i ~= b_i and a:intersects(b) then
- done = false
- break
- end
- end
- if not done then break end
- end
- pass = pass+1
- end
- return rooms
- end
- function Generator.generate(seed)
- math.randomseed(seed)
- local rooms = generate_rooms()
- -- Keeping the biggest rooms
- local biggest_rooms = filter(function(r) return r.width >= 4 and r.height >= 4 end, rooms)
- -- Generating their centers
- local centers = map(function(r) return Point(r.x+r.width/2, r.y+r.height/2) end, biggest_rooms)
- local triangles = Delaunay.triangulate(unpack(centers))
- local edges = {}
- for i, triangle in ipairs(triangles) do
- for _,edge in pairs({triangle.e1, triangle.e2, triangle.e3}) do
- local found = false
- for _,v in pairs(edges) do
- if v == edge then
- found = true
- break
- end
- end
- if not found then
- table.insert(edges, edge)
- end
- end
- end
- local graph = Graph(centers, edges)
- local res = graph
- if #edges > 3 then
- res = MST.search(graph,
- function(edge)
- local dx = edge.p1.x - edge.p2.x
- local dy = edge.p1.y - edge.p2.y
- return math.sqrt(dx*dx+dy*dy)
- end
- )
- end
- local m = Map(Generator.DIMENSION, Generator.DIMENSION)
- for _, r in pairs(biggest_rooms) do
- m:carve(r)
- end
- for _,edge in pairs(res.edges) do
- local vertices_ok = 0
- for _,c in pairs(centers) do
- if edge.p1.id ==c.id or edge.p2.id == c.id then
- vertices_ok = vertices_ok + 1
- end
- end
- if vertices_ok == 2 then
- Bresenham.los(math.floor(edge.p1.x), math.floor(edge.p1.y), math.floor(edge.p2.x), math.floor(edge.p2.y),
- function(x, y)
- m.tiles[y][x] = 0
- return true
- end
- )
- end
- end
- return m
- end
- return Generator
|