Last active
April 12, 2019 19:35
-
-
Save diamonax/94641af06c4c1fc02d5b5b70373fc526 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