JSFiddle - React, Tailwind, and code Playground
by Santiago J
CSS
canvas {
border: 1px solid;
}
JavaScript
const gridWidth = 20;
const gridHeight = 20;
const GRID_TO_PX = 8;
const px = x => x * GRID_TO_PX;
const canvas = document.createElement('canvas');
canvas.width = px(gridWidth);
canvas.height = px(gridHeight);
document.body.appendChild(canvas);
const ctx = canvas.getContext('2d');
const point = (x, y) => ({x, y});
const snake = [];
const UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4;
let direction, nextDirection;
let speed;
let food;
function init() {
direction = nextDirection = RIGHT;
speed = 2;
food = genFood();
snake.length = 0;
for (let i = 0; i < 3; i++) {
snake.unshift(point(i, 3));
}
}
init();
function pointEq(a, b) {
return a.x === b.x && a.y === b.y;
}
function isInSnake(point) {
for (const seg of snake) {
if (pointEq(point, seg)) return true;
}
return false;
}
function isInSnakeTail(point) {
for (let i = 1; i < snake.length; i++) {
if (pointEq(point, snake[i])) return true;
}
return false;
}
function genFood() {
while (true) {
const food = point(
Math.floor(Math.random() * gridWidth),
Math.floor(Math.random() * gridHeight));
if (!isInSnake(food)) return food;
}
}
function drawPoint(point) {
ctx.fillRect(px(point.x), px(point.y), px(1), px(1));
}
function loop() {
direction = nextDirection;
const oldHead = snake[0];
const dx = direction === LEFT ? -1 :direction === RIGHT ? 1 : 0;
const dy = direction === UP ? -1 :direction === DOWN ? 1 : 0;
const newHead = point(oldHead.x + dx, oldHead.y + dy);
snake.unshift(newHead);
const lost = isInSnakeTail(newHead) ||
newHead.x < 0 || newHead.x >= gridWidth ||
newHead.y < 0 || newHead.y >= gridHeight;
if (pointEq(newHead, food)) {
food = genFood();
speed++;
} else {
snake.pop();
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const seg of snake) drawPoint(seg);
drawPoint(food);
if (lost) {
alert('you lose!');
init();
}
setTimeout(loop, 1000 /...