Difference between revisions of "Levelgen gallery"

From Bitfighter
(Replacing page with 'Funcorners Mazeracer')
Line 1: Line 1:
 
[[Levelgen_example:_Funcorners|Funcorners]]
 
[[Levelgen_example:_Funcorners|Funcorners]]
 
+
[[Levelgen_example:_Mazeracer|Mazeracer]]
To use the following script, copy it into a file called "mazegen.lua" in your levels folder, and add the following line to your level file:
+
 
+
<source lang="levelcode">
+
Script mazegen.lua
+
</source>
+
 
+
or, to create a smaller maze:
+
 
+
<source lang="levelcode">
+
Script mazegen.lua 5 5 0 0 1
+
</source>
+
 
+
 
+
<source lang="lua">
+
-------------------------------------------------------------------------------
+
--
+
-- MazeGen script creates a random maze
+
-- Args: gridXSize, gridYSize, ulCornerX, ulCornerY, cellsize
+
--
+
--    gridXSize, gridYSize --> Number of cells in the maze (defaults to 10, 10)
+
--    ulCornerX, ulCornerY --> Coordinates of upper left corner of maze
+
--                        (defaults to 0, 0)
+
--    cellsize --> Size of each maze cell (defaults to 1)
+
--
+
-------------------------------------------------------------------------------
+
 
+
 
+
function isUnvisited(cell)
+
  return cell["N Wall"] and cell["S Wall"] and cell["E Wall"] and cell["W Wall"]
+
end
+
 
+
 
+
function getAdjacentUnvisitedCells(cell)
+
 
+
  local x = cell["x"]
+
  local y = cell["y"]
+
 
+
  adjCells = {}
+
  adjDirs = {}
+
 
+
  if(not cells[x][y]["N Edge"] and isUnvisited(cells[x][y - 1])) then
+
    table.insert(adjCells, cells[x][y - 1])
+
    table.insert(adjDirs, "N")
+
  end
+
 
+
  if(not cells[x][y]["S Edge"] and isUnvisited(cells[x][y + 1])) then
+
    table.insert(adjCells, cells[x][y + 1])
+
    table.insert(adjDirs, "S")
+
  end
+
 
+
  if(not cells[x][y]["E Edge"] and isUnvisited(cells[x + 1][y])) then
+
    table.insert(adjCells, cells[x + 1][y])
+
    table.insert(adjDirs, "E")
+
  end
+
 
+
  if(not cells[x][y]["W Edge"] and isUnvisited(cells[x - 1][y])) then
+
    table.insert(adjCells, cells[x - 1][y])
+
    table.insert(adjDirs, "W")
+
  end
+
end
+
 
+
 
+
-- Knock down wall to neighbor cell, and neighbor's wall to current cell
+
function knockDownWallToCell(cell, dir, adjacentCell)
+
  cell[dir .. " Wall"] = false
+
  adjacentCell[oppDir(dir) .. " Wall"] = false
+
end
+
 
+
 
+
function oppDir(dir)
+
  if(dir == "N") then return "S" end
+
  if(dir == "S") then return "N" end
+
  if(dir == "E") then return "W" end
+
  if(dir == "W") then return "E" end
+
end
+
 
+
 
+
function initGridCells(xsize, ysize)
+
  for x = 0, xsize + 1 do    -- Add extra cell to avoid bounds checking later
+
    cells[x] = {}
+
    for y = 0, ysize + 1 do
+
        cells[x][y] = {}
+
 
+
        cells[x][y]["N Wall"] = true
+
        cells[x][y]["S Wall"] = true
+
        cells[x][y]["E Wall"] = true
+
        cells[x][y]["W Wall"] = true
+
 
+
        cells[x][y]["x"] = x
+
        cells[x][y]["y"] = y
+
 
+
        cells[x][y]["N Edge"] = (y == 1)
+
        cells[x][y]["S Edge"] = (y == gridYSize)
+
        cells[x][y]["E Edge"] = (x == gridXSize)
+
        cells[x][y]["W Edge"] = (x == 1)
+
    end
+
  end
+
end
+
 
+
 
+
function outputMaze()
+
 
+
  -- We'll output our maze as a series of tiles, each being 2 x cellsize square
+
  -- Divide each tile into quadrants, as follows:
+
  --          X----+----+
+
  --          | UL | UR |    * denotes point (cenx, ceny)
+
  --          |    |    |    size of each cell is (gridXSize, gridXSize)
+
  --          +----*----+    coords of point X on upper left cell are
+
  --          | LL | LR |      (ulCornerX, ulCornerY)
+
  --          |    |    |    UL is always filled in, LR is always open
+
  --          +----+----+    LL is filled in when an E wall is present
+
  --                          UR is filled in when a N wall is present
+
  --  When a series of these tiles are tiled together, a maze will be drawn
+
  --  with an open bottom and open right side, which will be closed at the end.
+
  --
+
  --  Wall segments are drawn as 2-pt horizontal lines with the appropriate
+
  --  thickness to make them square.  Adjacent wall segments are partially
+
  --  merged into longer horizontal lines to reduce vertices and therefore
+
  --  level transfer size.  Note we're taking advantage of Bitfighter's vertex
+
  --  thinning algorithms to make our job just a bit easier.
+
 
+
  local gridsize = levelgen:getGridSize() + 1 -- Add 1 to get a tiny bit of
+
                                              -- overlap to make walls merge
+
  local wallsize = gridsize * cellsize
+
  local points
+
 
+
  for y = 1, gridYSize do
+
 
+
      local xpoints = { }
+
 
+
      for x = 1, gridXSize do
+
        local cenx = ulCornerX + (2 * x - 1) * cellsize
+
        local ceny = ulCornerY + (2 * y - 1) * cellsize
+
        local cell = cells[x][y]
+
 
+
 
+
        -- UL quadrant is always drawn
+
        if(#xpoints == 0) then        -- No line in progress
+
            xpoints = { Point(cenx - cellsize, ceny - cellsize * 0.5) }
+
        end
+
 
+
        -- UR quadrant drawn only when a N wall is present
+
      local endx
+
 
+
      if(cell["N Wall"]) then
+
        endx = cenx + cellsize
+
      else
+
        endx = cenx
+
        end
+
 
+
 
+
      if(not cell["N Wall"] or cell["E Edge"]) then
+
            table.insert(xpoints, Point(endx, ceny - cellsize * 0.5) )
+
 
+
          levelgen:addWall(wallsize, false, xpoints)
+
          xpoints = { }
+
      end
+
 
+
        -- LL quadrant drawn only when a W wall is present
+
        if(cell["W Wall"]) then
+
            local pts = { Point(cenx - cellsize, ceny + cellsize * 0.5),
+
                          Point(cenx            , ceny + cellsize * 0.5) }
+
            levelgen:addWall(wallsize, false, pts)
+
        end
+
 
+
        -- LR quadrant is always open, so do nothing
+
      end
+
 
+
  end
+
 
+
  -- Now add walls along entire bottom and right sides of the maze
+
  local pts = { Point(ulCornerX,
+
                    ulCornerY + 2 * gridYSize * cellsize + cellsize * 0.5),
+
                Point(ulCornerX + 2 * gridXSize * cellsize + cellsize * 0.5,
+
                      ulCornerY + 2 * gridYSize * cellsize + cellsize * 0.5),
+
                Point(ulCornerX + 2 * gridXSize * cellsize + cellsize * 0.5,
+
                      ulCornerY) }
+
  levelgen:addWall(wallsize, false, pts)
+
end
+
 
+
 
+
 
+
-----------------------------------------------------------
+
-----------------------------------------------------------
+
-----------------------------------------------------------
+
-----------------------------------------------------------
+
-----------------------------------------------------------
+
-----------------------------------------------------------
+
-----------------------------------------------------------
+
-----------------------------------------------------------
+
-----------------------------------------------------------
+
 
+
 
+
-- Global variables
+
 
+
-- Remember, in Bitfighter, all global variables must be
+
-- defined in the main block!
+
 
+
gridXSize = tonumber(arg[1])
+
gridYSize = tonumber(arg[2])
+
ulCornerX = tonumber(arg[3])
+
ulCornerY = tonumber(arg[4])
+
cellsize = tonumber(arg[5])
+
 
+
if gridXSize == nil then gridXSize = 10 end
+
if gridYSize == nil then gridYSize = 10 end
+
if ulCornerX == nil then ulCornerX = 0 end
+
if ulCornerY == nil then ulCornerY = 0 end
+
if cellsize == nil then cellsize = 1 end
+
 
+
 
+
cellStack = List:new()
+
 
+
cells = {}
+
adjCells = {}
+
adjDirs = {}
+
 
+
-- Initialize cells
+
initGridCells(gridXSize, gridYSize)
+
 
+
 
+
-- Get starting cell
+
local x = math.random(gridXSize)
+
local y = math.random(gridYSize)
+
 
+
local currCell = cells[x][y]
+
local totalCells = gridXSize * gridYSize
+
 
+
local visitedCells = 1
+
 
+
while visitedCells < totalCells do
+
 
+
  -- Find all adjacent cells with all walls intact (sets adjCells and adjDirs)
+
  getAdjacentUnvisitedCells(currCell)
+
  if(#adjCells > 0) then                  -- More than one?
+
    local adj = math.random(#adjCells)    -- Pick one at random
+
          knockDownWallToCell(currCell, adjDirs[adj], adjCells[adj])
+
 
+
          -- Push current cell location on the cellStack; we'll revisit it later
+
          cellStack:pushright(currCell)
+
 
+
          -- Make the randomly selected adjacent cell the new current cell
+
          currCell = adjCells[adj]
+
 
+
    visitedCells = visitedCells + 1
+
  else
+
    -- This cell has no neighbors, so let's grab one from the stack
+
    currCell = cellStack:popright()
+
  end
+
end
+
 
+
-- Output the results
+
outputMaze()
+
 
+
 
+
</source>
+

Revision as of 00:10, 29 October 2010

Funcorners Mazeracer