CCCPaste

raycast

local map = {
  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
  {1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1},
  {1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,1},
  {1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1},
  {1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1},
  {1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1},
  {1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1},
  {1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1},
  {1,0,1,1,1,0,1,1,1,1,1,0,1,1,0,1},
  {1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1},
  {1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1},
  {1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1},
  {1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1},
  {1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1},
  {1,0,1,0,1,1,1,0,1,1,1,0,1,1,0,1},
  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
}
local mapWidth, mapHeight = 16, 16
local player = {
  angle = 0,
  fov = math.pi / 3,
  speed = 3,
  rotSpeed = 0.003
}
local screenWidth, screenHeight = 800, 600
local halfHeight = screenHeight / 2
local rayCount = screenWidth / 2
function love.load()
  love.window.setMode(screenWidth, screenHeight)
  love.window.setTitle("Raycasting Maze")
  love.mouse.setRelativeMode(true)
end
function love.update(dt)
  local moveX, moveY = 0, 0
  if love.keyboard.isDown("w") then
    moveX = moveX + math.cos(player.angle) * player.speed * dt
    moveY = moveY + math.sin(player.angle) * player.speed * dt
  end
  if love.keyboard.isDown("s") then
    moveX = moveX - math.cos(player.angle) * player.speed * dt
    moveY = moveY - math.sin(player.angle) * player.speed * dt
  end
  if love.keyboard.isDown("a") then
    moveX = moveX + math.sin(player.angle) * player.speed * dt
    moveY = moveY - math.cos(player.angle) * player.speed * dt
  end
  if love.keyboard.isDown("d") then
    moveX = moveX - math.sin(player.angle) * player.speed * dt
    moveY = moveY + math.cos(player.angle) * player.speed * dt
  end
  local newX, newY = player.x + moveX, player.y + moveY
  if map[math.floor(player.y) + 1][math.floor(newX) + 1] == 0 then
    player.x = newX
  end
  if map[math.floor(newY) + 1][math.floor(player.x) + 1] == 0 then
    player.y = newY
  end
end
function love.mousemoved(_, _, dx)
  player.angle = player.angle + dx * player.rotSpeed
  if player.angle < 0 then
    player.angle = player.angle + 2 * math.pi
  elseif player.angle > 2 * math.pi then
    player.angle = player.angle - 2 * math.pi
  end
end
function love.draw()
  love.graphics.setColor(0.2, 0.2, 0.8)
  love.graphics.rectangle("fill", 0, 0, screenWidth, halfHeight)
  love.graphics.setColor(0.3, 0.3, 0.3)
  love.graphics.rectangle("fill", 0, halfHeight, screenWidth, halfHeight)
  local columnWidth = screenWidth / rayCount
  for col = 0, rayCount - 1 do
    local rayAngle = player.angle - player.fov / 2 + (col / rayCount) * player.fov
    local rayX, rayY = player.x, player.y
    local rayDirX, rayDirY = math.cos(rayAngle), math.sin(rayAngle)
    local mapX, mapY = math.floor(rayX), math.floor(rayY)
    local deltaDistX = math.abs(1 / rayDirX)
    local deltaDistY = math.abs(1 / rayDirY)
    local sideDistX, sideDistY
    local stepX, stepY
    local hit, side = false, 0
    if rayDirX < 0 then
      stepX = -1
      sideDistX = (rayX - mapX) * deltaDistX
    else
      stepX = 1
      sideDistX = (mapX + 1 - rayX) * deltaDistX
    end
    if rayDirY < 0 then
      stepY = -1
      sideDistY = (rayY - mapY) * deltaDistY
    else
      stepY = 1
      sideDistY = (mapY + 1 - rayY) * deltaDistY
    end
    while not hit do
      if sideDistX < sideDistY then
        sideDistX = sideDistX + deltaDistX
        mapX = mapX + stepX
        side = 0
      else
        sideDistY = sideDistY + deltaDistY
        mapY = mapY + stepY
        side = 1
      end
      if mapX < 0 or mapX >= mapWidth or mapY < 0 or mapY >= mapHeight then
        hit = true
      elseif map[mapY + 1][mapX + 1] == 1 then
        hit = true
      end
    end
    local perpDist = (side == 0)
      and (mapX - player.x + (1 - stepX) / 2) / rayDirX
      or (mapY - player.y + (1 - stepY) / 2) / rayDirY
    local lineHeight = screenHeight / perpDist
    local drawStart = math.max(0, -lineHeight / 2 + halfHeight)
    local drawEnd = math.min(screenHeight, lineHeight / 2 + halfHeight)
    if side == 0 then
      love.graphics.setColor(0.8, 0.2, 0.2)
    else
      love.graphics.setColor(0.5, 0.15, 0.15)
    end
    love.graphics.rectangle("fill",
      col * columnWidth,
      drawStart,
      columnWidth + 1,
      drawEnd - drawStart
    )
  end
  love.graphics.setColor(1, 1, 0)
  love.graphics.setLineWidth(1)
  love.graphics.line(screenWidth/2 - 5, halfHeight, screenWidth/2 + 5, halfHeight)
  love.graphics.line(screenWidth/2, halfHeight - 5, screenWidth/2, halfHeight + 5)
end
function love.keypressed(key)
  if key == "escape" then
    love.event.quit()
  end
end