Spaces:
Running
Running
| class SnakeGame extends HTMLElement { | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| .game-container { | |
| width: 400px; | |
| height: 400px; | |
| margin: 0 auto; | |
| background-color: rgba(15, 23, 42, 0.8); | |
| border: 2px solid rgba(99, 102, 241, 0.5); | |
| border-radius: 0.75rem; | |
| box-shadow: 0 0 30px rgba(99, 102, 241, 0.3); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .game-container::before { | |
| content: ""; | |
| position: absolute; | |
| inset: 0; | |
| background-image: | |
| linear-gradient(rgba(99, 102, 241, 0.1) 1px, transparent 1px), | |
| linear-gradient(90deg, rgba(99, 102, 241, 0.1) 1px, transparent 1px); | |
| background-size: 20px 20px; | |
| } | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .snake-body { | |
| position: absolute; | |
| width: 20px; | |
| height: 20px; | |
| background: linear-gradient(135deg, #6366f1, #8b5cf6); | |
| border-radius: 4px; | |
| box-shadow: 0 0 5px rgba(139, 92, 246, 0.7); | |
| z-index: 2; | |
| } | |
| .food { | |
| position: absolute; | |
| width: 16px; | |
| height: 16px; | |
| background: linear-gradient(135deg, #f43f5e, #f97316); | |
| border-radius: 50%; | |
| box-shadow: 0 0 10px rgba(244, 63, 94, 0.7); | |
| z-index: 2; | |
| animation: pulse 1s infinite alternate; | |
| } | |
| @keyframes pulse { | |
| from { transform: scale(1); } | |
| to { transform: scale(1.2); } | |
| } | |
| .controls { | |
| display: flex; | |
| justify-content: center; | |
| gap: 1rem; | |
| margin-top: 1rem; | |
| } | |
| button { | |
| padding: 0.5rem 1.5rem; | |
| background: linear-gradient(90deg, #6366f1, #8b5cf6); | |
| color: white; | |
| border: none; | |
| border-radius: 0.5rem; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.3s; | |
| box-shadow: 0 4px 6px rgba(99, 102, 241, 0.2); | |
| } | |
| button:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 12px rgba(99, 102, 241, 0.3); | |
| } | |
| .score { | |
| text-align: center; | |
| margin-top: 1rem; | |
| font-size: 1.2rem; | |
| background: linear-gradient(90deg, #6366f1, #8b5cf6); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| color: transparent; | |
| font-weight: bold; | |
| letter-spacing: 0.05em; | |
| } | |
| </style> | |
| <div class="game-container" id="game-board"></div> | |
| <div class="score">Score: <span id="score">0</span></div> | |
| <div class="controls"> | |
| <button id="start-btn">Start Game</button> | |
| <button id="reset-btn">Reset</button> | |
| </div> | |
| `; | |
| this.initGame(); | |
| } | |
| initGame() { | |
| const shadow = this.shadowRoot; | |
| const gameBoard = shadow.getElementById('game-board'); | |
| const scoreDisplay = shadow.getElementById('score'); | |
| const startBtn = shadow.getElementById('start-btn'); | |
| const resetBtn = shadow.getElementById('reset-btn'); | |
| // Game state | |
| let snake = [{x: 200, y: 200}]; | |
| let food = this.generateFood(); | |
| let direction = 'right'; | |
| let gameInterval; | |
| let score = 0; | |
| let gameSpeed = 150; | |
| let gameStarted = false; | |
| // Draw initial state | |
| this.drawGame(); | |
| // Event listeners | |
| startBtn.addEventListener('click', startGame); | |
| resetBtn.addEventListener('click', resetGame); | |
| document.addEventListener('keydown', changeDirection); | |
| function startGame() { | |
| if (gameStarted) return; | |
| gameStarted = true; | |
| gameInterval = setInterval(moveSnake, gameSpeed); | |
| } | |
| function resetGame() { | |
| clearInterval(gameInterval); | |
| snake = [{x: 200, y: 200}]; | |
| direction = 'right'; | |
| score = 0; | |
| scoreDisplay.textContent = '0'; | |
| gameStarted = false; | |
| this.drawGame(); | |
| } | |
| function changeDirection(e) { | |
| if (!gameStarted) return; | |
| const key = e.keyCode; | |
| if (key === 37 && direction !== 'right') direction = 'left'; | |
| else if (key === 38 && direction !== 'down') direction = 'up'; | |
| else if (key === 39 && direction !== 'left') direction = 'right'; | |
| else if (key === 40 && direction !== 'up') direction = 'down'; | |
| } | |
| function moveSnake() { | |
| const head = {...snake[0]}; | |
| switch(direction) { | |
| case 'up': head.y -= 20; break; | |
| case 'down': head.y += 20; break; | |
| case 'left': head.x -= 20; break; | |
| case 'right': head.x += 20; break; | |
| } | |
| // Check for collision with walls or self | |
| if (head.x < 0 || head.x >= 400 || head.y < 0 || head.y >= 400 || | |
| snake.some(segment => segment.x === head.x && segment.y === head.y)) { | |
| clearInterval(gameInterval); | |
| alert('Game Over! Your score: ' + score); | |
| return; | |
| } | |
| snake.unshift(head); | |
| // Check if snake ate food | |
| if (head.x === food.x && head.y === food.y) { | |
| score += 10; | |
| scoreDisplay.textContent = score; | |
| food = this.generateFood(); | |
| // Speed up game | |
| if (score % 50 === 0 && gameSpeed > 50) { | |
| gameSpeed -= 10; | |
| clearInterval(gameInterval); | |
| gameInterval = setInterval(moveSnake, gameSpeed); | |
| } | |
| } else { | |
| snake.pop(); | |
| } | |
| this.drawGame(); | |
| } | |
| this.generateFood = function() { | |
| const x = Math.floor(Math.random() * 20) * 20; | |
| const y = Math.floor(Math.random() * 20) * 20; | |
| // Make sure food doesn't spawn on snake | |
| if (snake.some(segment => segment.x === x && segment.y === y)) { | |
| return this.generateFood(); | |
| } | |
| return {x, y}; | |
| } | |
| this.drawGame = function() { | |
| gameBoard.innerHTML = ''; | |
| // Draw snake | |
| snake.forEach(segment => { | |
| const snakeElement = document.createElement('div'); | |
| snakeElement.className = 'snake-body'; | |
| snakeElement.style.left = segment.x + 'px'; | |
| snakeElement.style.top = segment.y + 'px'; | |
| gameBoard.appendChild(snakeElement); | |
| }); | |
| // Draw food | |
| const foodElement = document.createElement('div'); | |
| foodElement.className = 'food'; | |
| foodElement.style.left = food.x + 'px'; | |
| foodElement.style.top = food.y + 'px'; | |
| gameBoard.appendChild(foodElement); | |
| } | |
| } | |
| } | |
| customElements.define('snake-game', SnakeGame); |