-
-
Save gabrielflorit/f059df7a9d16a454455d9783c2985b82 to your computer and use it in GitHub Desktop.
SCRIPT-8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// title: 3D Maze | |
// move and turn by using the arrow keys | |
const { sin, cos, atan2, sqrt, floor, ceil, pow, random, max, sign, PI } = Math; | |
const MAPSIZE = 128; | |
const WIDTH = 128; | |
const HEIGHT = 128; | |
const grid = []; | |
for (let i = 0; i < MAPSIZE * MAPSIZE; i++) { | |
const cell = 1 + floor(random() * 4); | |
grid.push(random() < 0.3 ? cell : 0); | |
} | |
// clear path in front of starting position | |
grid[MAPSIZE / 2 * MAPSIZE + MAPSIZE / 2 + 0] = 0; | |
grid[MAPSIZE / 2 * MAPSIZE + MAPSIZE / 2 + 1] = 0; | |
grid[MAPSIZE / 2 * MAPSIZE + MAPSIZE / 2 + 2] = 0; | |
initialState = { | |
x: MAPSIZE / 2 + 0.5, | |
y: MAPSIZE / 2 + 0.5, | |
direction: 0.1, | |
grid: grid | |
}; | |
const getCell = (grid, x, y) => { | |
x = floor(x); | |
y = floor(y); | |
if (x < 0 || MAPSIZE <= x || y < 0 || MAPSIZE <= y) return -1; | |
return grid[y * MAPSIZE + x]; | |
}; | |
const fillRect = (x, y, w, h, c) => | |
rectFill(floor(x), floor(y), ceil(w), ceil(h), c); | |
update = (state, input) => { | |
const dx = (!!input.up - !!input.down) * cos(state.direction) * 0.05; | |
const dy = (!!input.down - !!input.up) * sin(state.direction) * 0.05; | |
if (getCell(state.grid, state.x + dx, state.y) <= 0) state.x += dx; | |
if (getCell(state.grid, state.x, state.y + dy) <= 0) state.y += dy; | |
state.direction += (!!input.left - !!input.right) * 0.04; | |
state.direction = (state.direction + 2 * PI) % (2 * PI); | |
}; | |
draw = ({ x, y, direction, grid }) => { | |
// dark outline | |
const OUTLINE = true; | |
const THICKNESS = 1; | |
// perspective | |
const FOV = PI / 3; | |
const RANGE = 20; | |
rectFill(0, 64, 128, 64, 0); // ceiling | |
rectFill(0, 0, 128, 64, 5); // floor | |
let prevwall = -1; | |
let prevheight = -1; | |
let prevdist = -1; | |
// ray casting | |
for (let i = 0; i < WIDTH; i++) { | |
const angle = direction - FOV / 2 + FOV / WIDTH * i; | |
const c = cos(angle); | |
const s = -sin(angle); | |
let px = x; | |
let py = y; | |
let wallX = -1; | |
let wallY = -1; | |
let dist = 0; | |
while (dist < RANGE) { | |
let horX = (c > 0 ? floor(px + 1) : ceil(px - 1)) - px; | |
let verY = (s > 0 ? floor(py + 1) : ceil(py - 1)) - py; | |
let horY = horX * s / c; | |
let verX = verY * c / s; | |
let distX = sqrt(horX * horX + horY * horY); | |
let distY = sqrt(verX * verX + verY * verY); | |
const t = distX < distY; | |
px += t ? horX : verX; | |
py += t ? horY : verY; | |
dist += t ? distX : distY; | |
const dx = t ? sign(c) * 0.5 : 0; | |
const dy = t ? 0 : sign(s) * 0.5; | |
if (getCell(grid, px + dx, py + dy) > 0) { | |
wallX = floor(px + dx); | |
wallY = floor(py + dy); | |
} | |
if (wallX >= 0 && wallY >= 0) break; | |
} | |
if (dist === 0) dist = RANGE; | |
let height = -1; | |
let z = -1; | |
// rendering | |
if (wallX >= 0 && wallY >= 0) { | |
z = dist * cos(angle - direction); | |
height = HEIGHT / z; | |
const top = HEIGHT / 2 - height / 2; | |
const cell = getCell(grid, wallX, wallY); | |
if (cell > 0) fillRect(WIDTH - i - 1, top, 1, height, cell); | |
if (OUTLINE) { | |
let w = (1 - z / RANGE) * THICKNESS; | |
fillRect(WIDTH - i - 1, top, w, w, 7); | |
fillRect(WIDTH - i - 1, top + height, w, w, 7); | |
if (prevwall != wallY * MAPSIZE + wallX) { | |
const maxheight = max(prevheight, height); | |
const maxtop = HEIGHT / 2 - maxheight / 2; | |
if (maxheight > height) { | |
w = (1 - prevdist / RANGE) * THICKNESS; | |
} | |
fillRect(WIDTH - i - 1, maxtop, w, maxheight, 7); | |
} | |
} | |
} else if (OUTLINE) { | |
if (prevwall != -1) { | |
let maxtop = HEIGHT / 2 - prevheight / 2; | |
let w = (1 - HEIGHT / prevheight / RANGE) * THICKNESS; | |
fillRect(WIDTH - i - 1, maxtop, w, prevheight, 7); | |
} | |
wallX = -1; | |
wallY = 0; | |
} | |
prevwall = wallY * MAPSIZE + wallX; | |
prevheight = height; | |
prevdist = z; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment