Ibrokhim1263's picture
Add 3 files
dd7ab0c verified
raw
history blame
17.5 kB
<!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>
/* Custom styles for the game canvas */
.game-container {
position: relative;
margin: 0 auto;
border: 8px solid #4B5563;
border-radius: 8px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}
canvas {
display: block;
background-color: #1F2937;
}
.game-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.7);
color: white;
font-size: 2rem;
z-index: 10;
}
.snake-cell {
transition: all 0.1s ease;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.pulse {
animation: pulse 0.5s infinite;
}
</style>
</head>
<body class="bg-gray-900 min-h-screen flex flex-col items-center justify-center p-4">
<div class="text-center mb-6">
<h1 class="text-4xl font-bold text-green-400 mb-2">🐍 Snake Game</h1>
<p class="text-gray-300">Use arrow keys or swipe to control the snake</p>
</div>
<div class="game-container relative">
<canvas id="gameCanvas" width="400" height="400"></canvas>
<div id="gameOverlay" class="game-overlay hidden">
<h2 class="text-4xl font-bold text-red-500 mb-4">Game Over!</h2>
<p class="text-xl mb-6">Your score: <span id="finalScore" class="text-green-400 font-bold">0</span></p>
<button id="restartBtn" class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-6 rounded-full transition-all transform hover:scale-105">
Play Again
</button>
</div>
<div id="startScreen" class="game-overlay flex">
<div class="text-center">
<h2 class="text-4xl font-bold text-green-400 mb-6 pulse">Ready to Play?</h2>
<button id="startBtn" class="bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-8 rounded-full text-xl transition-all transform hover:scale-105">
Start Game
</button>
<div class="mt-8 text-left text-gray-300">
<p class="flex items-center mb-2"><span class="inline-block w-6 mr-2">🔼</span> Move Up</p>
<p class="flex items-center mb-2"><span class="inline-block w-6 mr-2">🔽</span> Move Down</p>
<p class="flex items-center mb-2"><span class="inline-block w-6 mr-2">◀️</span> Move Left</p>
<p class="flex items-center"><span class="inline-block w-6 mr-2">▶️</span> Move Right</p>
</div>
</div>
</div>
</div>
<div class="mt-6 flex justify-between w-full max-w-md">
<div class="bg-gray-800 p-4 rounded-lg text-center flex-1 mx-2">
<p class="text-gray-400">Score</p>
<p id="score" class="text-2xl font-bold text-green-400">0</p>
</div>
<div class="bg-gray-800 p-4 rounded-lg text-center flex-1 mx-2">
<p class="text-gray-400">High Score</p>
<p id="highScore" class="text-2xl font-bold text-yellow-400">0</p>
</div>
</div>
<div class="mt-8 grid grid-cols-4 gap-2 md:hidden">
<button id="upBtn" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-4 rounded-full transition-all">
</button>
<div class="col-span-2"></div>
<button id="leftBtn" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-4 rounded-full transition-all">
</button>
<button id="downBtn" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-4 rounded-full transition-all">
</button>
<button id="rightBtn" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-4 rounded-full transition-all">
</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Game variables
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const highScoreElement = document.getElementById('highScore');
const gameOverlay = document.getElementById('gameOverlay');
const startScreen = document.getElementById('startScreen');
const finalScoreElement = document.getElementById('finalScore');
const restartBtn = document.getElementById('restartBtn');
const startBtn = document.getElementById('startBtn');
// Mobile controls
const upBtn = document.getElementById('upBtn');
const downBtn = document.getElementById('downBtn');
const leftBtn = document.getElementById('leftBtn');
const rightBtn = document.getElementById('rightBtn');
// Game settings
const gridSize = 20;
const tileCount = canvas.width / gridSize;
let speed = 7;
// Game state
let snake = [];
let food = {};
let direction = 'right';
let nextDirection = 'right';
let score = 0;
let highScore = localStorage.getItem('snakeHighScore') || 0;
let gameRunning = false;
let gameLoop;
// Initialize game
highScoreElement.textContent = highScore;
// Event listeners
document.addEventListener('keydown', changeDirection);
restartBtn.addEventListener('click', resetGame);
startBtn.addEventListener('click', startGame);
// Mobile controls
upBtn.addEventListener('click', () => changeDirection({keyCode: 38}));
downBtn.addEventListener('click', () => changeDirection({keyCode: 40}));
leftBtn.addEventListener('click', () => changeDirection({keyCode: 37}));
rightBtn.addEventListener('click', () => changeDirection({keyCode: 39}));
// Touch controls for swipe
let touchStartX = 0;
let touchStartY = 0;
canvas.addEventListener('touchstart', (e) => {
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
}, false);
canvas.addEventListener('touchmove', (e) => {
if (!touchStartX || !touchStartY) return;
const touchEndX = e.touches[0].clientX;
const touchEndY = e.touches[0].clientY;
const diffX = touchStartX - touchEndX;
const diffY = touchStartY - touchEndY;
if (Math.abs(diffX) > Math.abs(diffY)) {
// Horizontal swipe
if (diffX > 0 && direction !== 'right') {
nextDirection = 'left';
} else if (diffX < 0 && direction !== 'left') {
nextDirection = 'right';
}
} else {
// Vertical swipe
if (diffY > 0 && direction !== 'down') {
nextDirection = 'up';
} else if (diffY < 0 && direction !== 'up') {
nextDirection = 'down';
}
}
touchStartX = 0;
touchStartY = 0;
e.preventDefault();
}, false);
function startGame() {
startScreen.classList.add('hidden');
resetGame();
}
function resetGame() {
// Reset snake
snake = [];
for (let i = 3; i >= 0; i--) {
snake.push({x: i, y: 0});
}
// Reset game state
direction = 'right';
nextDirection = 'right';
score = 0;
scoreElement.textContent = score;
gameOverlay.classList.add('hidden');
gameRunning = true;
// Create first food
createFood();
// Start game loop
if (gameLoop) clearInterval(gameLoop);
gameLoop = setInterval(gameUpdate, 1000 / speed);
}
function gameUpdate() {
// Update direction
direction = nextDirection;
// Move snake
const head = {x: snake[0].x, y: snake[0].y};
switch (direction) {
case 'up':
head.y--;
break;
case 'down':
head.y++;
break;
case 'left':
head.x--;
break;
case 'right':
head.x++;
break;
}
// Check wall collision
if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
gameOver();
return;
}
// Check self collision
for (let i = 0; i < snake.length; i++) {
if (snake[i].x === head.x && snake[i].y === head.y) {
gameOver();
return;
}
}
// Check food collision
if (head.x === food.x && head.y === food.y) {
// Don't remove tail (snake grows)
createFood();
score++;
scoreElement.textContent = score;
// Increase speed slightly every 5 points
if (score % 5 === 0) {
speed += 0.5;
clearInterval(gameLoop);
gameLoop = setInterval(gameUpdate, 1000 / speed);
}
} else {
// Remove tail
snake.pop();
}
// Add new head
snake.unshift(head);
// Draw everything
drawGame();
}
function drawGame() {
// Clear canvas
ctx.fillStyle = '#1F2937';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw grid lines
ctx.strokeStyle = '#374151';
ctx.lineWidth = 0.5;
for (let i = 0; i < tileCount; i++) {
// Vertical lines
ctx.beginPath();
ctx.moveTo(i * gridSize, 0);
ctx.lineTo(i * gridSize, canvas.height);
ctx.stroke();
// Horizontal lines
ctx.beginPath();
ctx.moveTo(0, i * gridSize);
ctx.lineTo(canvas.width, i * gridSize);
ctx.stroke();
}
// Draw snake
snake.forEach((segment, index) => {
// Head is different color
if (index === 0) {
ctx.fillStyle = '#10B981'; // Head color
} else {
// Gradient body color
const hue = 120 - (index * 2);
ctx.fillStyle = `hsl(${hue}, 80%, 50%)`;
}
ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize - 1, gridSize - 1);
// Add eyes to head
if (index === 0) {
ctx.fillStyle = 'white';
// Eye positions based on direction
if (direction === 'right') {
ctx.fillRect((segment.x * gridSize) + 12, (segment.y * gridSize) + 4, 4, 4);
ctx.fillRect((segment.x * gridSize) + 12, (segment.y * gridSize) + 12, 4, 4);
} else if (direction === 'left') {
ctx.fillRect((segment.x * gridSize) + 4, (segment.y * gridSize) + 4, 4, 4);
ctx.fillRect((segment.x * gridSize) + 4, (segment.y * gridSize) + 12, 4, 4);
} else if (direction === 'up') {
ctx.fillRect((segment.x * gridSize) + 4, (segment.y * gridSize) + 4, 4, 4);
ctx.fillRect((segment.x * gridSize) + 12, (segment.y * gridSize) + 4, 4, 4);
} else if (direction === 'down') {
ctx.fillRect((segment.x * gridSize) + 4, (segment.y * gridSize) + 12, 4, 4);
ctx.fillRect((segment.x * gridSize) + 12, (segment.y * gridSize) + 12, 4, 4);
}
}
});
// Draw food
ctx.fillStyle = '#EF4444';
ctx.beginPath();
const centerX = (food.x * gridSize) + (gridSize / 2);
const centerY = (food.y * gridSize) + (gridSize / 2);
const radius = (gridSize / 2) - 2;
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
ctx.fill();
// Add shine to food
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
ctx.beginPath();
ctx.arc(centerX - 3, centerY - 3, 3, 0, Math.PI * 2);
ctx.fill();
}
function createFood() {
food = {
x: Math.floor(Math.random() * tileCount),
y: Math.floor(Math.random() * tileCount)
};
// Make sure food doesn't appear on snake
for (let i = 0; i < snake.length; i++) {
if (snake[i].x === food.x && snake[i].y === food.y) {
createFood();
return;
}
}
}
function changeDirection(e) {
// Prevent opposite direction movement
switch (e.keyCode) {
case 37: // Left
if (direction !== 'right') nextDirection = 'left';
break;
case 38: // Up
if (direction !== 'down') nextDirection = 'up';
break;
case 39: // Right
if (direction !== 'left') nextDirection = 'right';
break;
case 40: // Down
if (direction !== 'up') nextDirection = 'down';
break;
}
}
function gameOver() {
gameRunning = false;
clearInterval(gameLoop);
// Update high score
if (score > highScore) {
highScore = score;
highScoreElement.textContent = highScore;
localStorage.setItem('snakeHighScore', highScore);
}
finalScoreElement.textContent = score;
gameOverlay.classList.remove('hidden');
}
// Initial draw
drawGame();
});
</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=Ibrokhim1263/https-huggingface-co-ibrokhim1263" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>