snake-game / index.html
x3v's picture
Add 2 files
1d9042b verified
<!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>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.pulse-animation {
animation: pulse 1.5s infinite;
}
.game-over {
background-color: rgba(239, 68, 68, 0.9);
}
.snake-head {
background-color: #10b981;
border-radius: 30%;
z-index: 10;
}
.snake-body {
background-color: #34d399;
border-radius: 40%;
}
.food {
background-color: #ef4444;
border-radius: 50%;
box-shadow: 0 0 10px #ef4444;
}
.grid-cell {
transition: background-color 0.1s ease;
}
@media (max-width: 640px) {
.controls {
display: grid !important;
}
}
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen flex flex-col items-center justify-center p-4">
<div class="max-w-4xl w-full">
<div class="flex justify-between items-center mb-4">
<h1 class="text-3xl md:text-4xl font-bold text-green-400">🐍 Snake Game</h1>
<div class="flex items-center space-x-4">
<div class="bg-gray-800 px-4 py-2 rounded-lg">
<span class="text-gray-300">Score:</span>
<span id="score" class="text-white font-bold ml-2">0</span>
</div>
<div class="bg-gray-800 px-4 py-2 rounded-lg">
<span class="text-gray-300">High:</span>
<span id="high-score" class="text-white font-bold ml-2">0</span>
</div>
</div>
</div>
<div class="relative">
<div id="game-board" class="bg-gray-800 rounded-lg overflow-hidden border-2 border-gray-700 shadow-lg mx-auto"
style="width: 400px; height: 400px; display: grid; grid-template-rows: repeat(20, 1fr); grid-template-columns: repeat(20, 1fr);">
<!-- Game grid will be generated by JavaScript -->
</div>
<div id="game-over" class="absolute inset-0 flex flex-col items-center justify-center bg-opacity-90 rounded-lg hidden game-over">
<h2 class="text-4xl font-bold mb-4">Game Over!</h2>
<p class="text-xl mb-6">Your score: <span id="final-score" class="font-bold">0</span></p>
<button id="restart-btn" class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-6 rounded-full transition duration-200 pulse-animation">
Play Again
</button>
</div>
<div id="start-screen" class="absolute inset-0 flex flex-col items-center justify-center bg-gray-800 bg-opacity-90 rounded-lg">
<h2 class="text-4xl font-bold mb-6 text-green-400">Snake Game</h2>
<p class="text-gray-300 mb-8 text-center px-4">Use arrow keys or buttons to control the snake. Eat the red food to grow!</p>
<button id="start-btn" class="bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-8 rounded-full transition duration-200 pulse-animation">
Start Game
</button>
</div>
</div>
<div class="mt-6 flex justify-center">
<div class="controls hidden md:flex space-x-4">
<button id="up-btn" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-4 px-6 rounded-lg transition duration-200">
↑
</button>
<div class="flex flex-col space-y-4">
<button id="left-btn" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-4 px-6 rounded-lg transition duration-200">
←
</button>
<button id="right-btn" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-4 px-6 rounded-lg transition duration-200">
β†’
</button>
</div>
<button id="down-btn" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-4 px-6 rounded-lg transition duration-200">
↓
</button>
</div>
</div>
<div class="mt-8 text-center text-gray-400">
<p>Press spacebar to pause/resume the game</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Game variables
const GRID_SIZE = 20;
const gameBoard = document.getElementById('game-board');
const scoreDisplay = document.getElementById('score');
const highScoreDisplay = document.getElementById('high-score');
const finalScoreDisplay = document.getElementById('final-score');
const gameOverScreen = document.getElementById('game-over');
const startScreen = document.getElementById('start-screen');
const startBtn = document.getElementById('start-btn');
const restartBtn = document.getElementById('restart-btn');
const upBtn = document.getElementById('up-btn');
const downBtn = document.getElementById('down-btn');
const leftBtn = document.getElementById('left-btn');
const rightBtn = document.getElementById('right-btn');
let snake = [{x: 10, y: 10}];
let food = generateFood();
let direction = 'right';
let nextDirection = 'right';
let gameSpeed = 150;
let score = 0;
let highScore = localStorage.getItem('snakeHighScore') || 0;
let gameInterval;
let isPaused = false;
let isGameOver = false;
highScoreDisplay.textContent = highScore;
// Create game grid
function createGrid() {
gameBoard.innerHTML = '';
for (let i = 0; i < GRID_SIZE; i++) {
for (let j = 0; j < GRID_SIZE; j++) {
const cell = document.createElement('div');
cell.classList.add('grid-cell', 'border', 'border-gray-700');
cell.style.gridRow = i + 1;
cell.style.gridColumn = j + 1;
gameBoard.appendChild(cell);
}
}
}
// Generate food at random position
function generateFood() {
let newFood;
while (!newFood || isOnSnake(newFood)) {
newFood = {
x: Math.floor(Math.random() * GRID_SIZE),
y: Math.floor(Math.random() * GRID_SIZE)
};
}
return newFood;
}
// Check if position is occupied by snake
function isOnSnake(position) {
return snake.some(segment => segment.x === position.x && segment.y === position.y);
}
// Draw game state
function draw() {
// Clear board
const cells = document.querySelectorAll('.grid-cell');
cells.forEach(cell => {
cell.className = 'grid-cell border border-gray-700';
});
// Draw snake
snake.forEach((segment, index) => {
const cellIndex = segment.y * GRID_SIZE + segment.x;
if (cells[cellIndex]) {
if (index === 0) {
cells[cellIndex].classList.add('snake-head');
} else {
cells[cellIndex].classList.add('snake-body');
}
}
});
// Draw food
const foodIndex = food.y * GRID_SIZE + food.x;
if (cells[foodIndex]) {
cells[foodIndex].classList.add('food');
}
}
// Update game state
function update() {
if (isPaused || isGameOver) return;
direction = nextDirection;
// Move snake
const head = {...snake[0]};
switch (direction) {
case 'up':
head.y--;
break;
case 'down':
head.y++;
break;
case 'left':
head.x--;
break;
case 'right':
head.x++;
break;
}
// Check collision with walls
if (head.x < 0 || head.x >= GRID_SIZE || head.y < 0 || head.y >= GRID_SIZE) {
gameOver();
return;
}
// Check collision with self
if (snake.some(segment => segment.x === head.x && segment.y === head.y)) {
gameOver();
return;
}
snake.unshift(head);
// Check if snake ate food
if (head.x === food.x && head.y === food.y) {
score += 10;
scoreDisplay.textContent = score;
food = generateFood();
// Increase speed slightly as score increases
if (score % 50 === 0 && gameSpeed > 70) {
gameSpeed -= 5;
clearInterval(gameInterval);
gameInterval = setInterval(update, gameSpeed);
}
} else {
snake.pop();
}
draw();
}
// Game over
function gameOver() {
isGameOver = true;
clearInterval(gameInterval);
// Update high score
if (score > highScore) {
highScore = score;
localStorage.setItem('snakeHighScore', highScore);
highScoreDisplay.textContent = highScore;
}
finalScoreDisplay.textContent = score;
gameOverScreen.classList.remove('hidden');
}
// Start game
function startGame() {
snake = [{x: 10, y: 10}];
food = generateFood();
direction = 'right';
nextDirection = 'right';
score = 0;
scoreDisplay.textContent = score;
gameSpeed = 150;
isPaused = false;
isGameOver = false;
startScreen.classList.add('hidden');
gameOverScreen.classList.add('hidden');
createGrid();
draw();
clearInterval(gameInterval);
gameInterval = setInterval(update, gameSpeed);
}
// Event listeners
document.addEventListener('keydown', (e) => {
switch (e.key) {
case 'ArrowUp':
if (direction !== 'down') nextDirection = 'up';
e.preventDefault();
break;
case 'ArrowDown':
if (direction !== 'up') nextDirection = 'down';
e.preventDefault();
break;
case 'ArrowLeft':
if (direction !== 'right') nextDirection = 'left';
e.preventDefault();
break;
case 'ArrowRight':
if (direction !== 'left') nextDirection = 'right';
e.preventDefault();
break;
case ' ':
if (!isGameOver) {
isPaused = !isPaused;
if (isPaused) {
clearInterval(gameInterval);
} else {
gameInterval = setInterval(update, gameSpeed);
}
}
break;
}
});
startBtn.addEventListener('click', startGame);
restartBtn.addEventListener('click', startGame);
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';
});
// Initialize
createGrid();
draw();
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=x3v/snake-game" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>