| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Neon Snake Game</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); |
| |
| body { |
| font-family: 'Press Start 2P', cursive; |
| background-color: #0f172a; |
| overflow: hidden; |
| } |
| |
| #game-board { |
| border: 4px solid #4f46e5; |
| box-shadow: 0 0 20px #4f46e5, inset 0 0 20px #4f46e5; |
| position: relative; |
| } |
| |
| .snake-segment { |
| background-color: #10b981; |
| border: 1px solid #a7f3d0; |
| box-shadow: 0 0 10px #10b981; |
| border-radius: 3px; |
| } |
| |
| .food { |
| background-color: #ef4444; |
| border-radius: 50%; |
| box-shadow: 0 0 15px #ef4444; |
| animation: pulse 0.8s infinite alternate; |
| } |
| |
| @keyframes pulse { |
| from { transform: scale(0.9); } |
| to { transform: scale(1.1); } |
| } |
| |
| .glow-text { |
| text-shadow: 0 0 10px currentColor; |
| } |
| |
| .modal-overlay { |
| background-color: rgba(15, 23, 42, 0.9); |
| } |
| |
| .modal-content { |
| border: 3px solid #4f46e5; |
| box-shadow: 0 0 30px #4f46e5; |
| } |
| </style> |
| </head> |
| <body class="min-h-screen flex flex-col items-center justify-center p-4"> |
| <div class="text-center mb-6"> |
| <h1 class="text-4xl md:text-5xl font-bold text-indigo-400 glow-text mb-2">NEON SNAKE</h1> |
| <div class="flex justify-center items-center gap-6 text-emerald-400"> |
| <div class="flex items-center gap-2"> |
| <i class="fas fa-star"></i> |
| <span id="score" class="text-xl">0</span> |
| </div> |
| <div class="flex items-center gap-2"> |
| <i class="fas fa-tachometer-alt"></i> |
| <span id="speed" class="text-xl">1</span> |
| </div> |
| </div> |
| </div> |
| |
| <div class="relative"> |
| <canvas id="game-board" width="400" height="400" class="bg-gray-900"></canvas> |
| |
| <div id="game-over-modal" class="fixed inset-0 flex items-center justify-center modal-overlay hidden"> |
| <div class="bg-gray-800 p-8 rounded-lg modal-content text-center max-w-md w-full"> |
| <h2 class="text-3xl text-red-500 glow-text mb-4">GAME OVER!</h2> |
| <p class="text-indigo-300 mb-6">Your score: <span id="final-score" class="text-emerald-400">0</span></p> |
| <div class="flex flex-col space-y-3"> |
| <button id="restart-btn" class="bg-emerald-600 hover:bg-emerald-500 text-white py-3 px-6 rounded transition"> |
| <i class="fas fa-redo mr-2"></i> Play Again |
| </button> |
| <button id="quit-btn" class="bg-indigo-600 hover:bg-indigo-500 text-white py-3 px-6 rounded transition"> |
| <i class="fas fa-times mr-2"></i> Quit |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| <div id="start-modal" class="fixed inset-0 flex items-center justify-center modal-overlay"> |
| <div class="bg-gray-800 p-8 rounded-lg modal-content text-center max-w-md w-full"> |
| <h2 class="text-3xl text-indigo-400 glow-text mb-6">NEON SNAKE</h2> |
| <div class="mb-8 text-left text-indigo-200"> |
| <div class="flex items-center mb-3"> |
| <i class="fas fa-arrow-up text-xl w-8"></i> |
| <span>Move Up</span> |
| </div> |
| <div class="flex items-center mb-3"> |
| <i class="fas fa-arrow-down text-xl w-8"></i> |
| <span>Move Down</span> |
| </div> |
| <div class="flex items-center mb-3"> |
| <i class="fas fa-arrow-left text-xl w-8"></i> |
| <span>Move Left</span> |
| </div> |
| <div class="flex items-center mb-3"> |
| <i class="fas fa-arrow-right text-xl w-8"></i> |
| <span>Move Right</span> |
| </div> |
| <div class="flex items-center"> |
| <i class="fas fa-space-shuttle text-xl w-8"></i> |
| <span>Pause Game</span> |
| </div> |
| </div> |
| <button id="start-btn" class="bg-emerald-600 hover:bg-emerald-500 text-white py-3 px-8 rounded-lg text-lg transition"> |
| <i class="fas fa-play mr-2"></i> Start Game |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| <div class="mt-6 text-center text-indigo-300 text-sm"> |
| <p>Use arrow keys to control the snake. Collect food to grow!</p> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', () => { |
| const canvas = document.getElementById('game-board'); |
| const ctx = canvas.getContext('2d'); |
| const scoreElement = document.getElementById('score'); |
| const speedElement = document.getElementById('speed'); |
| const finalScoreElement = document.getElementById('final-score'); |
| const gameOverModal = document.getElementById('game-over-modal'); |
| const startModal = document.getElementById('start-modal'); |
| const startBtn = document.getElementById('start-btn'); |
| const restartBtn = document.getElementById('restart-btn'); |
| const quitBtn = document.getElementById('quit-btn'); |
| |
| const gridSize = 20; |
| const tileCount = canvas.width / gridSize; |
| let speed = 1; |
| let score = 0; |
| let gameRunning = false; |
| let gamePaused = false; |
| |
| |
| let snake = [ |
| {x: 10, y: 10} |
| ]; |
| let velocityX = 0; |
| let velocityY = 0; |
| let nextVelocityX = 0; |
| let nextVelocityY = 0; |
| |
| |
| let foodX = 5; |
| let foodY = 5; |
| |
| |
| let lastRenderTime = 0; |
| let gameOver = false; |
| |
| |
| function initGame() { |
| snake = [{x: 10, y: 10}]; |
| velocityX = 0; |
| velocityY = 0; |
| nextVelocityX = 0; |
| nextVelocityY = 0; |
| score = 0; |
| speed = 1; |
| gameOver = false; |
| gameRunning = true; |
| gamePaused = false; |
| scoreElement.textContent = score; |
| speedElement.textContent = speed; |
| placeFood(); |
| window.requestAnimationFrame(gameLoop); |
| } |
| |
| |
| function gameLoop(currentTime) { |
| if (gameOver || !gameRunning) return; |
| |
| window.requestAnimationFrame(gameLoop); |
| |
| const secondsSinceLastRender = (currentTime - lastRenderTime) / (1000 / (7 + speed)); |
| if (secondsSinceLastRender < 1) return; |
| lastRenderTime = currentTime; |
| |
| if (!gamePaused) { |
| update(); |
| } |
| draw(); |
| } |
| |
| |
| function update() { |
| |
| velocityX = nextVelocityX; |
| velocityY = nextVelocityY; |
| |
| |
| const head = {x: snake[0].x + velocityX, y: snake[0].y + velocityY}; |
| |
| |
| if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) { |
| gameOver = true; |
| endGame(); |
| return; |
| } |
| |
| |
| for (let i = 0; i < snake.length; i++) { |
| if (head.x === snake[i].x && head.y === snake[i].y) { |
| gameOver = true; |
| endGame(); |
| return; |
| } |
| } |
| |
| |
| snake.unshift(head); |
| |
| |
| if (head.x === foodX && head.y === foodY) { |
| |
| score += speed * 10; |
| scoreElement.textContent = score; |
| |
| |
| if (score > 0 && score % 50 === 0) { |
| speed++; |
| speedElement.textContent = speed; |
| } |
| |
| placeFood(); |
| } else { |
| |
| snake.pop(); |
| } |
| } |
| |
| |
| function draw() { |
| |
| ctx.fillStyle = '#1e293b'; |
| ctx.fillRect(0, 0, canvas.width, canvas.height); |
| |
| |
| ctx.strokeStyle = '#334155'; |
| ctx.lineWidth = 0.5; |
| for (let i = 0; i < tileCount; i++) { |
| ctx.beginPath(); |
| ctx.moveTo(i * gridSize, 0); |
| ctx.lineTo(i * gridSize, canvas.height); |
| ctx.stroke(); |
| |
| ctx.beginPath(); |
| ctx.moveTo(0, i * gridSize); |
| ctx.lineTo(canvas.width, i * gridSize); |
| ctx.stroke(); |
| } |
| |
| |
| snake.forEach((segment, index) => { |
| |
| const intensity = index === 0 ? 1 : 0.6 - (index * 0.01); |
| ctx.fillStyle = `rgba(16, 185, 129, ${intensity})`; |
| ctx.strokeStyle = `rgba(167, 243, 208, ${intensity})`; |
| |
| ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize); |
| ctx.strokeRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize); |
| }); |
| |
| |
| ctx.fillStyle = '#ef4444'; |
| ctx.beginPath(); |
| ctx.arc( |
| foodX * gridSize + gridSize / 2, |
| foodY * gridSize + gridSize / 2, |
| gridSize / 2 - 2, |
| 0, |
| Math.PI * 2 |
| ); |
| ctx.fill(); |
| |
| |
| if (gamePaused) { |
| ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'; |
| ctx.font = '20px "Press Start 2P"'; |
| ctx.textAlign = 'center'; |
| ctx.fillText('PAUSED', canvas.width / 2, canvas.height / 2); |
| } |
| } |
| |
| |
| function placeFood() { |
| let validPosition = false; |
| |
| while (!validPosition) { |
| foodX = Math.floor(Math.random() * tileCount); |
| foodY = Math.floor(Math.random() * tileCount); |
| |
| validPosition = true; |
| |
| |
| for (let i = 0; i < snake.length; i++) { |
| if (snake[i].x === foodX && snake[i].y === foodY) { |
| validPosition = false; |
| break; |
| } |
| } |
| } |
| } |
| |
| |
| function endGame() { |
| gameRunning = false; |
| finalScoreElement.textContent = score; |
| gameOverModal.classList.remove('hidden'); |
| } |
| |
| |
| document.addEventListener('keydown', (e) => { |
| if (!gameRunning && e.key === ' ') { |
| startBtn.click(); |
| return; |
| } |
| |
| switch (e.key) { |
| case 'ArrowUp': |
| if (velocityY === 0 && !gamePaused) { |
| nextVelocityX = 0; |
| nextVelocityY = -1; |
| } |
| break; |
| case 'ArrowDown': |
| if (velocityY === 0 && !gamePaused) { |
| nextVelocityX = 0; |
| nextVelocityY = 1; |
| } |
| break; |
| case 'ArrowLeft': |
| if (velocityX === 0 && !gamePaused) { |
| nextVelocityX = -1; |
| nextVelocityY = 0; |
| } |
| break; |
| case 'ArrowRight': |
| if (velocityX === 0 && !gamePaused) { |
| nextVelocityX = 1; |
| nextVelocityY = 0; |
| } |
| break; |
| case ' ': |
| if (gameRunning) { |
| gamePaused = !gamePaused; |
| } |
| break; |
| } |
| }); |
| |
| startBtn.addEventListener('click', () => { |
| startModal.classList.add('hidden'); |
| initGame(); |
| }); |
| |
| restartBtn.addEventListener('click', () => { |
| gameOverModal.classList.add('hidden'); |
| initGame(); |
| }); |
| |
| quitBtn.addEventListener('click', () => { |
| gameOverModal.classList.add('hidden'); |
| startModal.classList.remove('hidden'); |
| }); |
| |
| |
| let touchStartX = 0; |
| let touchStartY = 0; |
| |
| canvas.addEventListener('touchstart', (e) => { |
| touchStartX = e.touches[0].clientX; |
| touchStartY = e.touches[0].clientY; |
| e.preventDefault(); |
| }, false); |
| |
| canvas.addEventListener('touchmove', (e) => { |
| if (!touchStartX || !touchStartY || gamePaused) 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)) { |
| if (diffX > 0 && velocityX === 0) { |
| |
| nextVelocityX = -1; |
| nextVelocityY = 0; |
| } else if (diffX < 0 && velocityX === 0) { |
| |
| nextVelocityX = 1; |
| nextVelocityY = 0; |
| } |
| } |
| |
| else { |
| if (diffY > 0 && velocityY === 0) { |
| |
| nextVelocityX = 0; |
| nextVelocityY = -1; |
| } else if (diffY < 0 && velocityY === 0) { |
| |
| nextVelocityX = 0; |
| nextVelocityY = 1; |
| } |
| } |
| |
| touchStartX = 0; |
| touchStartY = 0; |
| e.preventDefault(); |
| }, false); |
| |
| |
| canvas.addEventListener('click', () => { |
| if (gameRunning) { |
| gamePaused = !gamePaused; |
| } |
| }); |
| }); |
| </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=Atum09/gg" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |