function love.load() p2 = math.pi / 2 p3 = 3 * math.pi / 2 fov = 30 love.graphics.setBackgroundColor(0.3, 0.3, 0.3, 1) love.window.setMode(1024, 512) player = {} player["x"] = 100 player["y"] = 110 player["size"] = 8 player["angle"] = -math.pi / 2 player["dx"] = math.cos(player.angle) * 5 player["dy"] = math.sin(player.angle) * 5 player["offset"] = 20 map = {} map["x"] = 8 map["y"] = 8 map["size"] = 64 map["map"] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, } end function love.update() if love.keyboard.isDown("a") then player.angle = player.angle - 0.1 if player.angle < 0 then player.angle = player.angle + 2 * math.pi end player.dx = math.cos(player.angle) * 5 player.dy = math.sin(player.angle) * 5 end if love.keyboard.isDown("d") then player.angle = player.angle + 0.1 if player.angle > 2 * math.pi then player.angle = player.angle - 2 * math.pi end player.dx = math.cos(player.angle) * 5 player.dy = math.sin(player.angle) * 5 end local xo = 0 if player.dx < 0 then xo = -player.offset else xo = player.offset end local yo = 0 if player.dy < 0 then yo = -player.offset else yo = player.offset end local ipx = math.ceil(player.x / map.size) local ipx_add_xo = math.ceil((player.x + xo) / map.size) local ipx_sub_xo = math.ceil((player.x - xo) / map.size) local ipy = math.ceil(player.y / map.size) local ipy_add_yo = math.ceil((player.y + yo) / map.size) local ipy_sub_yo = math.ceil((player.y - yo) / map.size) local pos1 = (ipy - 1)*map.x + ipx_add_xo local pos2 = (ipy_add_yo - 1)*map.x + ipx if love.keyboard.isDown("w") then if map.map[pos1] == 0 then player.x = player.x + player.dx end if map.map[pos2] == 0 then player.y = player.y + player.dy end end local pos3 = (ipy - 1)*map.x + ipx_sub_xo local pos4 = (ipy_sub_yo - 1)*map.x + ipx if love.keyboard.isDown("s") then if map.map[pos3] == 0 then player.x = player.x - player.dx end if map.map[pos4] == 0 then player.y = player.y - player.dy end end end function love.draw() drawMap() drawPlayer() drawRays3D() end function drawPlayer() love.graphics.setColor(1, 1, 0) love.graphics.rectangle("fill", player.x - player.size / 2, player.y - player.size / 2, player.size, player.size ) love.graphics.line(player.x, player.y, player.x + player.dx * 5, player.y + player.dy * 5) end function drawMap() for y = 1, map.y do for x = 1, map.x do local color = map.map[(y - 1) * map.x + x] love.graphics.setColor(color, color, color) local xo = (x - 1) * map.size local yo = (y - 1) * map.size love.graphics.polygon("fill", xo + 1, yo + 1, xo + 1, yo + map.size - 1, xo + map.size - 1, yo + map.size - 1, xo + map.size - 1, yo + 1 ) end end end function dist(ax, ay, bx, by, ang) return math.sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay)) end function drawRays3D() local ray = {} ray["angle"] = player.angle - math.rad(fov) ray["x"] = 0 ray["y"] = 0 ray["xo"] = 0 ray["yo"] = 0 ray["mx"] = 0 ray["my"] = 0 ray["mp"] = 0 if ray.angle < 0 then ray.angle = ray.angle + 2 * math.pi end if ray.angle > 2 * math.pi then ray.angle = ray.angle - 2 * math.pi end for r = 1, fov * 2 do local dof = 0 local disT = 0 local disH = 1000000 local hx = player.x local hy = player.y local aTan = -1 / math.tan(ray.angle) if (ray.angle > math.pi) then ray.y = bit.lshift(bit.rshift(player.y, 6), 6) - 0.0001 ray.x = (player.y - ray.y) * aTan + player.x ray.yo = -map.size ray.xo = -ray.yo * aTan end if (ray.angle < math.pi) then ray.y = bit.lshift(bit.rshift(player.y, 6), 6) + map.size ray.x = (player.y - ray.y) * aTan + player.x ray.yo = map.size ray.xo = -ray.yo * aTan end if ray.angle == 0 or ray.angle == math.pi then ray.x = player.x ray.y = player.y dof = 8 end while dof < 8 do ray.mx = bit.rshift(ray.x, 6) ray.my = bit.rshift(ray.y, 6) ray.mp = ray.my * map.x + ray.mx if ray.mp > 0 and ray.mp < (map.x * map.y + 1) and map.map[ray.mp + 1] == 1 then hx = ray.x hy = ray.y disH = dist(player.x, player.y, hx, hy, ray.angle) dof = 8 else ray.x = ray.x + ray.xo ray.y = ray.y + ray.yo dof = dof + 1 end end dof = 0 local disV = 1000000 local vx = player.x local vy = player.y local nTan = -math.tan(ray.angle) if (ray.angle > p2 and ray.angle < p3) then ray.x = bit.lshift(bit.rshift(player.x, 6), 6) - 0.0001 ray.y = (player.x - ray.x) * nTan + player.y ray.xo = -map.size ray.yo = -ray.xo * nTan end if (ray.angle < p2 or ray.angle > p3) then ray.x = bit.lshift(bit.rshift(player.x, 6), 6) + map.size ray.y = (player.x - ray.x) * nTan + player.y ray.xo = map.size ray.yo = -ray.xo * nTan end if ray.angle == 0 or ray.angle == math.pi then ray.x = player.x ray.y = player.y dof = 8 end while dof < 8 do ray.mx = bit.rshift(ray.x, 6) ray.my = bit.rshift(ray.y, 6) ray.mp = ray.my * map.x + ray.mx if ray.mp > 0 and ray.mp < (map.x * map.y + 1) and map.map[ray.mp + 1] == 1 then vx = ray.x vy = ray.y disV = dist(player.x, player.y, vx, vy, ray.angle) dof = 8 else ray.x = ray.x + ray.xo ray.y = ray.y + ray.yo dof = dof + 1 end end if disV < disH then ray.x = vx ray.y = vy disT = disV love.graphics.setColor(0.9, 0, 0) end if disH < disV then ray.x = hx ray.y = hy disT = disH love.graphics.setColor(0.7, 0, 0) end love.graphics.setLineWidth(1) love.graphics.line( player.x, player.y, ray.x, ray.y ) local ca = player.angle - ray.angle if ca < 0 then ca = ca + 2 * math.pi end if ca > 2 * math.pi then ca = ca - 2 * math.pi end disT = disT * math.cos(ca) local lineH = map.size * 320 / disT if lineH > 320 then lineH = 320 end local lineO = 160 - lineH / 2 love.graphics.setLineWidth(8) love.graphics.line( r * 8 + 530, lineO, r * 8 + 530, lineH + lineO ) ray.angle = ray.angle + math.rad(1) if ray.angle < 0 then ray.angle = ray.angle + 2 * math.pi end if ray.angle > 2 * math.pi then ray.angle = ray.angle - 2 * math.pi end end end