Published
Edited
May 23, 2020
1 star
Insert cell
Insert cell
// keyboard control: J(←), K(↑), L(→)
doc = html`
<div class="three">
<canvas class="mymap" width="${CellSizeX*WIDTH}" height="${CellSizeY*HEIGHT}">
</div>`
Insert cell
canvas = doc.querySelector("canvas")
Insert cell
ctx = canvas.getContext("2d")
Insert cell
drawMap()
Insert cell
setInterval( stepRoad, 80 )
Insert cell
WIDTH = 80
Insert cell
HEIGHT = 50
Insert cell
OFFROAD = 0
Insert cell
THEROAD = 1
Insert cell
RoadWidth = 14
Insert cell
CellSizeX = 5
Insert cell
CellSizeY = 13
Insert cell
theMap = {
const m = Array(HEIGHT).fill( Array(WIDTH).fill(OFFROAD) )
m.forEach( row => row.splice( WIDTH/2-RoadWidth/2, RoadWidth,
...Array(RoadWidth).fill(THEROAD) ) )
return m
}
Insert cell
rotateR = arr => arr.unshift( arr.pop() )
Insert cell
rotateL = arr => arr.push( arr.shift() )
Insert cell
drawMap = () => {
ctx.beginPath()
ctx.fillStyle = "black"
ctx.fillRect(0,0,CellSizeX*WIDTH,CellSizeY*HEIGHT)
ctx.closePath()
for (let i=0; i < HEIGHT; ++i)
for (let j=0; j < WIDTH; ++j) {
if(THEROAD==theMap[i][j]) {
ctx.beginPath()
ctx.fillStyle="yellow"
ctx.fillRect(j*CellSizeX,i*CellSizeY,CellSizeX,CellSizeY)
ctx.closePath()
}
}
}
Insert cell
style = html`
<style>
canvas {
background: #ddd; display: block;
margin-left: auto; margin-right: auto;
}

.three { perspective: 510px; }
.three > .mymap { margin-left:auto; margin-right:auto; transform: rotateX(66deg); }
</style>
`
Insert cell
dRoad = () => {
const r = Math.random();
return (r <= 1/3)? -1: (r > 2/3)? 1: 0;
}
Insert cell
theCar = {
return { // car object
pos: WIDTH/2, // x축 위치
dir: 0, // 이동방향 - 왼쪽(-1), 제자리(0), 오른쪽(1)
move() {
this.pos += this.dir;
this.pos = (this.pos<0)? 0: (this.pos>=WIDTH)? WIDTH-1: this.pos; // 맨 끝에서는 map 바깥으로 빠져나가지 않게
}
}
}
Insert cell
document.addEventListener("keydown", driveCar)
Insert cell
driveCar = e => {
switch (e.code) {
case "KeyJ": theCar.dir =-1; break; // 좌
case "KeyK": theCar.dir = 0; break; // 상 (제자리)
case "KeyL": theCar.dir = 1; break; // 우
default: break;
}
}
Insert cell
stepRoad = () => {
const row = theMap[0].map(x => x) // 새로운 row를 맵에서 가장 위의 row에서 복사해 생성
const first = row[0]
const last = row[WIDTH-1]
switch ( dRoad() ) { // 새로운 row의 길을 랜덤값에 따라 적절히 이동
case 0: break;
case 1: if ( last==OFFROAD) { rotateR(row) } else { rotateL(row) } break;
case -1: if (first==OFFROAD) { rotateL(row) } else { rotateR(row) } break;
}
theMap.pop() // 맵의 맨 아래 row 제거
theMap.unshift(row) // 맵의 맨 위에 새로운 row를 추가
drawMap() // 맵 그리기
theCar.move() // 자동차 이동
drawCar() // 자동차를 맵에 그림
}
Insert cell
drawCar = () => {
ctx.beginPath()
ctx.fillStyle = "magenta"
ctx.fillRect(theCar.pos*CellSizeX,(HEIGHT-1)*CellSizeY,CellSizeX,CellSizeY)
ctx.closePath()
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more