<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
color: #fff;
padding: 20px;
overflow-x: hidden;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
gap: 25px;
max-width: 800px;
width: 100%;
}
header {
text-align: center;
margin-bottom: 10px;
}
h1 {
font-size: 3.2rem;
margin-bottom: 8px;
background: linear-gradient(90deg, #00dbde, #fc00ff);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
text-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.subtitle {
font-size: 1.1rem;
opacity: 0.8;
margin-bottom: 5px;
}
.game-area {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 30px;
width: 100%;
}
.game-board {
position: relative;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
border: 3px solid #0f3460;
}
canvas {
background-color: #0f3460;
display: block;
}
.game-info {
background: rgba(15, 52, 96, 0.7);
border-radius: 12px;
padding: 25px;
min-width: 250px;
display: flex;
flex-direction: column;
gap: 20px;
border: 2px solid #1a5a9e;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.score-container {
text-align: center;
background: rgba(0, 0, 0, 0.3);
padding: 15px;
border-radius: 10px;
}
.score-title {
font-size: 1.2rem;
margin-bottom: 8px;
color: #a3d9ff;
}
#score {
font-size: 3.5rem;
font-weight: bold;
color: #00ff9d;
text-shadow: 0 0 10px rgba(0, 255, 157, 0.5);
}
.high-score {
font-size: 1.1rem;
color: #ffcc00;
margin-top: 5px;
}
.controls {
display: flex;
flex-direction: column;
gap: 15px;
}
.control-group {
background: rgba(0, 0, 0, 0.3);
padding: 15px;
border-radius: 10px;
}
.control-title {
font-size: 1.1rem;
margin-bottom: 10px;
color: #a3d9ff;
}
.key {
display: inline-block;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 6px;
padding: 5px 10px;
margin: 3px;
font-family: monospace;
font-weight: bold;
color: #fff;
}
.buttons {
display: flex;
flex-direction: column;
gap: 12px;
}
button {
padding: 14px;
border: none;
border-radius: 8px;
font-size: 1.1rem;
font-weight: bold;
cursor: pointer;
transition: all 0.2s ease;
color: white;
}
#startBtn {
background: linear-gradient(90deg, #00b09b, #96c93d);
}
#startBtn:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 176, 155, 0.4);
}
#resetBtn {
background: linear-gradient(90deg, #ff416c, #ff4b2b);
}
#resetBtn:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(255, 65, 108, 0.4);
}
#pauseBtn {
background: linear-gradient(90deg, #8a2387, #f27121);
}
#pauseBtn:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(138, 35, 135, 0.4);
}
.instructions {
background: rgba(15, 52, 96, 0.7);
border-radius: 12px;
padding: 20px;
width: 100%;
margin-top: 10px;
border: 2px solid #1a5a9e;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.instructions h3 {
color: #a3d9ff;
margin-bottom: 15px;
font-size: 1.3rem;
}
.instructions ul {
list-style-type: none;
padding-left: 10px;
}
.instructions li {
margin-bottom: 10px;
padding-left: 20px;
position: relative;
}
.instructions li:before {
content: "•";
color: #00ff9d;
font-size: 1.5rem;
position: absolute;
left: 0;
top: -3px;
}
.mobile-controls {
display: none;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 10px;
margin-top: 20px;
max-width: 300px;
}
.mobile-btn {
background: rgba(255, 255, 255, 0.15);
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
width: 70px;
height: 70px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.8rem;
color: white;
cursor: pointer;
user-select: none;
}
.mobile-btn.up {
grid-column: 2;
grid-row: 1;
}
.mobile-btn.left {
grid-column: 1;
grid-row: 2;
}
.mobile-btn.right {
grid-column: 3;
grid-row: 2;
}
.mobile-btn.down {
grid-column: 2;
grid-row: 3;
}
.game-status {
font-size: 1.2rem;
padding: 10px 20px;
border-radius: 8px;
background: rgba(0, 0, 0, 0.3);
text-align: center;
margin-top: 5px;
min-height: 48px;
display: flex;
align-items: center;
justify-content: center;
}
#status {
font-weight: bold;
color: #ffcc00;
}
footer {
margin-top: 25px;
text-align: center;
font-size: 0.9rem;
opacity: 0.7;
}
@media (max-width: 768px) {
.game-area {
flex-direction: column;
align-items: center;
}
.mobile-controls {
display: grid;
}
h1 {
font-size: 2.5rem;
}
}
@media (max-width: 480px) {
.game-info {
width: 100%;
}
canvas {
width: 300px;
height: 300px;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>Snake Game</h1>
<p class="subtitle">Classic arcade game rebuilt with HTML5 Canvas</p>
</header>
<div class="game-area">
<div class="game-board">
<canvas id="gameCanvas" width="500" height="500"></canvas>
</div>
<div class="game-info">
<div class="score-container">
<div class="score-title">SCORE</div>
<div id="score">0</div>
<div class="high-score">High Score: <span id="highScore">0</span></div>
</div>
<div class="game-status">
Status: <span id="status">Ready to play</span>
</div>
<div class="controls">
<div class="control-group">
<div class="control-title">KEYBOARD CONTROLS</div>
<p>
<span class="key">↑</span>
<span class="key">↓</span>
<span class="key">←</span>
<span class="key">→</span> Arrow Keys<br>
<span class="key">W</span>
<span class="key">A</span>
<span class="key">S</span>
<span class="key">D</span> WASD Keys<br>
<span class="key">SPACE</span> Pause/Resume
</p>
</div>
<div class="buttons">
<button id="startBtn">START GAME</button>
<button id="pauseBtn">PAUSE / RESUME</button>
<button id="resetBtn">RESET GAME</button>
</div>
</div>
</div>
</div>
<div class="mobile-controls">
<div class="mobile-btn up" id="upBtn">↑</div>
<div class="mobile-btn left" id="leftBtn">←</div>
<div class="mobile-btn right" id="rightBtn">→</div>
<div class="mobile-btn down" id="downBtn">↓</div>
</div>
<div class="instructions">
<h3>How to Play</h3>
<ul>
<li>Use arrow keys or WASD to control the snake direction.</li>
<li>Eat the red food to grow longer and increase your score.</li>
<li>Avoid hitting the walls or the snake's own body.</li>
<li>Each food gives you 10 points. Try to beat your high score!</li>
<li>Press SPACE or the PAUSE button to pause/resume the game.</li>
</ul>
</div>
<footer>
<p>Snake Game • Built with HTML5 Canvas, CSS3 & JavaScript • Enjoy!</p>
</footer>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const highScoreElement = document.getElementById('highScore');
const statusElement = document.getElementById('status');
const startBtn = document.getElementById('startBtn');
const pauseBtn = document.getElementById('pauseBtn');
const resetBtn = document.getElementById('resetBtn');
const upBtn = document.getElementById('upBtn');
const downBtn = document.getElementById('downBtn');
const leftBtn = document.getElementById('leftBtn');
const rightBtn = document.getElementById('rightBtn');
const gridSize = 20;
const gridWidth = canvas.width / gridSize;
const gridHeight = canvas.height / gridSize;
let snake = [];
let food = {};
let direction = 'right';
let nextDirection = 'right';
let gameSpeed = 120; let score = 0;
let highScore = localStorage.getItem('snakeHighScore') || 0;
let gameRunning = false;
let gamePaused = false;
let gameLoop;
highScoreElement.textContent = highScore;
function initGame() {
snake = [
{x: 5, y: 10},
{x: 4, y: 10},
{x: 3, y: 10}
];
generateFood();
direction = 'right';
nextDirection = 'right';
score = 0;
scoreElement.textContent = score;
statusElement.textContent = 'Ready to play';
statusElement.style.color = '#ffcc00';
draw();
}
function generateFood() {
let foodOnSnake;
do {
foodOnSnake = false;
food = {
x: Math.floor(Math.random() * gridWidth),
y: Math.floor(Math.random() * gridHeight)
};
for (let segment of snake) {
if (segment.x === food.x && segment.y === food.y) {
foodOnSnake = true;
break;
}
}
} while (foodOnSnake);
}
function draw() {
ctx.fillStyle = '#0f3460';
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawGrid();
for (let i = 0; i < snake.length; i++) {
const segment = snake[i];
if (i === 0) {
ctx.fillStyle = '#00ff9d';
ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize);
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
ctx.fillRect(segment.x * gridSize + 3, segment.y * gridSize + 3, gridSize - 6, 4);
ctx.fillStyle = '#000';
const eyeSize = 3;
const eyeOffset = 5;
if (direction === 'right') {
ctx.fillRect(segment.x * gridSize + gridSize - eyeOffset, segment.y * gridSize + eyeOffset, eyeSize, eyeSize);
ctx.fillRect(segment.x * gridSize + gridSize - eyeOffset, segment.y * gridSize + gridSize - eyeOffset - eyeSize, eyeSize, eyeSize);
} else if (direction === 'left') {
ctx.fillRect(segment.x * gridSize + eyeOffset, segment.y * gridSize + eyeOffset, eyeSize, eyeSize);
ctx.fillRect(segment.x * gridSize + eyeOffset, segment.y * gridSize + gridSize - eyeOffset - eyeSize, eyeSize, eyeSize);
} else if (direction === 'up') {
ctx.fillRect(segment.x * gridSize + eyeOffset, segment.y * gridSize + eyeOffset, eyeSize, eyeSize);
ctx.fillRect(segment.x * gridSize + gridSize - eyeOffset - eyeSize, segment.y * gridSize + eyeOffset, eyeSize, eyeSize);
} else if (direction === 'down') {
ctx.fillRect(segment.x * gridSize + eyeOffset, segment.y * gridSize + gridSize - eyeOffset, eyeSize, eyeSize);
ctx.fillRect(segment.x * gridSize + gridSize - eyeOffset - eyeSize, segment.y * gridSize + gridSize - eyeOffset, eyeSize, eyeSize);
}
}
else {
const colorValue = Math.max(50, 255 - (i * 15));
ctx.fillStyle = `rgb(0, ${colorValue}, ${150 - i * 5})`;
ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize);
ctx.fillStyle = `rgba(0, ${colorValue + 30}, ${180 - i * 5}, 0.3)`;
ctx.fillRect(segment.x * gridSize + 2, segment.y * gridSize + 2, gridSize - 4, gridSize - 4);
}
ctx.strokeStyle = '#000';
ctx.lineWidth = 1;
ctx.strokeRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize);
}
ctx.fillStyle = '#ff416c';
ctx.beginPath();
ctx.arc(
food.x * gridSize + gridSize / 2,
food.y * gridSize + gridSize / 2,
gridSize / 2 - 2,
0,
Math.PI * 2
);
ctx.fill();
ctx.fillStyle = 'rgba(255, 255, 255, 0.6)';
ctx.beginPath();
ctx.arc(
food.x * gridSize + gridSize / 2 - 3,
food.y * gridSize + gridSize / 2 - 3,
3,
0,
Math.PI * 2
);
ctx.fill();
}
function drawGrid() {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)';
ctx.lineWidth = 1;
for (let x = 0; x <= canvas.width; x += gridSize) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
}
for (let y = 0; y <= canvas.height; y += gridSize) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
}
function update() {
direction = nextDirection;
const head = {...snake[0]};
switch (direction) {
case 'up':
head.y -= 1;
break;
case 'down':
head.y += 1;
break;
case 'left':
head.x -= 1;
break;
case 'right':
head.x += 1;
break;
}
if (head.x < 0 || head.x >= gridWidth || head.y < 0 || head.y >= gridHeight) {
gameOver();
return;
}
for (let segment of snake) {
if (head.x === segment.x && head.y === segment.y) {
gameOver();
return;
}
}
snake.unshift(head);
if (head.x === food.x && head.y === food.y) {
score += 10;
scoreElement.textContent = score;
if (score > highScore) {
highScore = score;
highScoreElement.textContent = highScore;
localStorage.setItem('snakeHighScore', highScore);
}
generateFood();
if (score % 50 === 0 && gameSpeed > 50) {
gameSpeed -= 5;
clearInterval(gameLoop);
gameLoop = setInterval(gameStep, gameSpeed);
}
} else {
snake.pop();
}
draw();
}
function gameStep() {
if (gameRunning && !gamePaused) {
update();
}
}
function startGame() {
if (!gameRunning) {
initGame();
gameRunning = true;
gamePaused = false;
statusElement.textContent = 'Game running';
statusElement.style.color = '#00ff9d';
gameLoop = setInterval(gameStep, gameSpeed);
startBtn.textContent = 'RESTART GAME';
} else {
resetGame();
startGame();
}
}
function togglePause() {
if (!gameRunning) return;
gamePaused = !gamePaused;
if (gamePaused) {
statusElement.textContent = 'Game paused';
statusElement.style.color = '#ffcc00';
pauseBtn.textContent = 'RESUME GAME';
} else {
statusElement.textContent = 'Game running';
statusElement.style.color = '#00ff9d';
pauseBtn.textContent = 'PAUSE GAME';
}
}
function resetGame() {
clearInterval(gameLoop);
gameRunning = false;
gamePaused = false;
gameSpeed = 120;
initGame();
statusElement.textContent = 'Ready to play';
statusElement.style.color = '#ffcc00';
startBtn.textContent = 'START GAME';
pauseBtn.textContent = 'PAUSE / RESUME';
}
function gameOver() {
gameRunning = false;
clearInterval(gameLoop);
statusElement.textContent = 'Game Over! Press START to play again';
statusElement.style.color = '#ff416c';
let flashCount = 0;
const flashInterval = setInterval(() => {
if (flashCount % 2 === 0) {
ctx.fillStyle = 'rgba(255, 65, 108, 0.5)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
} else {
draw();
}
flashCount++;
if (flashCount >= 6) {
clearInterval(flashInterval);
draw();
}
}, 200);
}
function handleKeyDown(e) {
switch (e.key) {
case 'ArrowUp':
case 'w':
case 'W':
if (direction !== 'down') nextDirection = 'up';
e.preventDefault();
break;
case 'ArrowDown':
case 's':
case 'S':
if (direction !== 'up') nextDirection = 'down';
e.preventDefault();
break;
case 'ArrowLeft':
case 'a':
case 'A':
if (direction !== 'right') nextDirection = 'left';
e.preventDefault();
break;
case 'ArrowRight':
case 'd':
case 'D':
if (direction !== 'left') nextDirection = 'right';
e.preventDefault();
break;
case ' ':
togglePause();
e.preventDefault();
break;
case 'Enter':
startGame();
e.preventDefault();
break;
}
}
startBtn.addEventListener('click', startGame);
pauseBtn.addEventListener('click', togglePause);
resetBtn.addEventListener('click', resetGame);
upBtn.addEventListener('click', () => { if (direction !== 'down') nextDirection = 'up'; });
downBtn.addEventListener('click', () => { if (direction !== 'up') nextDirection = 'down'; });
leftBtn.addEventListener('click', () => { if (direction !== 'right') nextDirection = 'left'; });
rightBtn.addEventListener('click', () => { if (direction !== 'left') nextDirection = 'right'; });
document.addEventListener('keydown', handleKeyDown);
window.addEventListener('load', initGame);
canvas.addEventListener('contextmenu', e => e.preventDefault());
</script>
</body>
</html>