Untitled
unknown
plain_text
8 months ago
5.5 kB
7
Indexable
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Simple Snake Game</title>
<style>
body { display:flex; align-items:center; justify-content:center; height:100vh; margin:0;
background:#111; color:#eee; font-family:Arial, sans-serif; }
canvas { background:#0b3d0b; border:6px solid #072; box-shadow:0 6px 20px rgba(0,0,0,0.7); }
.info { position:fixed; top:12px; left:12px; font-size:14px; opacity:0.9; }
</style>
</head>
<body>
<div class="info">Use arrow keys to move • Space = pause • R = restart</div>
<canvas id="game" width="480" height="480"></canvas>
<script>
(() => {
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const TILE = 20; // size of one cell
const COLS = canvas.width / TILE;
const ROWS = canvas.height / TILE;
let speed = 8; // frames per second (snake speed)
let tick = 0;
// Game state
let snake = [{x: Math.floor(COLS/2), y: Math.floor(ROWS/2)}];
let dir = {x: 1, y: 0}; // initial direction: right
let nextDir = {...dir};
let food = spawnFood();
let score = 0;
let running = true;
let gameOver = false;
// Main loop using requestAnimationFrame with fixed-step logic
let lastTime = 0;
function loop(time) {
requestAnimationFrame(loop);
if (!lastTime) lastTime = time;
const delta = (time - lastTime) / 1000;
lastTime = time;
tick += delta * speed;
if (tick >= 1) {
tick = 0;
update();
draw();
}
}
function update() {
if (!running) return;
// apply buffered direction (prevents reversing instantly)
if ((nextDir.x !== -dir.x || nextDir.y !== -dir.y)) {
dir = {...nextDir};
}
const head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
// wrap-around (optional) OR collide with walls — we'll wrap
if (head.x < 0) head.x = COLS - 1;
if (head.x >= COLS) head.x = 0;
if (head.y < 0) head.y = ROWS - 1;
if (head.y >= ROWS) head.y = 0;
// check self-collision
if (snake.some(s => s.x === head.x && s.y === head.y)) {
gameOver = true;
running = false;
return;
}
snake.unshift(head);
// eat food?
if (head.x === food.x && head.y === food.y) {
score += 1;
// slight speed up every 5 points
if (score % 5 === 0) speed = Math.min(speed + 1, 20);
food = spawnFood();
} else {
snake.pop(); // move forward (remove tail)
}
}
function draw() {
// background
ctx.fillStyle = '#082208';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// draw food
drawRect(food.x, food.y, '#e53935');
// draw snake with gradient
for (let i = 0; i < snake.length; i++) {
const s = snake[i];
// head brighter
if (i === 0) drawRect(s.x, s.y, '#b7ffb7');
else {
const shade = Math.floor(60 + 150 * (i / snake.length));
drawRect(s.x, s.y, `rgb(${shade/2}, ${shade}, ${shade/2})`);
}
}
// HUD
ctx.fillStyle = 'rgba(0,0,0,0.4)';
ctx.fillRect(6, 6, 120, 34);
ctx.fillStyle = '#fff';
ctx.font = '16px Arial';
ctx.fillText('Score: ' + score, 12, 30);
if (!running && !gameOver) {
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(0, canvas.height/2 - 40, canvas.width, 80);
ctx.fillStyle = '#fff';
ctx.textAlign = 'center';
ctx.font = '24px Arial';
ctx.fillText('Paused — press Space to resume', canvas.width/2, canvas.height/2 + 8);
ctx.textAlign = 'start';
}
if (gameOver) {
ctx.fillStyle = 'rgba(0,0,0,0.7)';
ctx.fillRect(0, canvas.height/2 - 60, canvas.width, 120);
ctx.fillStyle = '#fff';
ctx.textAlign = 'center';
ctx.font = '32px Arial';
ctx.fillText('Game Over', canvas.width/2, canvas.height/2 - 6);
ctx.font = '18px Arial';
ctx.fillText('Score: ' + score + ' • Click or press R to restart', canvas.width/2, canvas.height/2 + 24);
ctx.textAlign = 'start';
}
}
function drawRect(cx, cy, color) {
ctx.fillStyle = color;
ctx.fillRect(cx * TILE + 1, cy * TILE + 1, TILE - 2, TILE - 2);
}
function spawnFood() {
while (true) {
const pos = { x: randInt(0, COLS-1), y: randInt(0, ROWS-1) };
if (!snake.some(s => s.x === pos.x && s.y === pos.y)) return pos;
}
}
function randInt(a, b) { return Math.floor(Math.random()*(b-a+1)) + a; }
// input
window.addEventListener('keydown', (e) => {
if (e.key === 'ArrowUp') nextDir = {x:0, y:-1};
else if (e.key === 'ArrowDown') nextDir = {x:0, y:1};
else if (e.key === 'ArrowLeft') nextDir = {x:-1, y:0};
else if (e.key === 'ArrowRight') nextDir = {x:1, y:0};
else if (e.key === ' ') { running = !running; e.preventDefault(); } // space = pause
else if (e.key.toLowerCase() === 'r') restart();
});
// mouse restart when game over
canvas.addEventListener('click', () => { if (gameOver) restart(); });
function restart() {
snake = [{x: Math.floor(COLS/2), y: Math.floor(ROWS/2)}];
dir = {x:1,y:0}; nextDir = {...dir};
food = spawnFood();
score = 0; speed = 8; running = true; gameOver = false;
}
// start
draw();
requestAnimationFrame(loop);
})();
</script>
</body>
</html>
Editor is loading...
Leave a Comment