176 lines
4.8 KiB
JavaScript
176 lines
4.8 KiB
JavaScript
// HTML elements
|
|
const board = document.getElementById('game-board');
|
|
const instructionText = document.getElementById('instruction-text');
|
|
const logo = document.getElementById('logo');
|
|
const score = document.getElementById('score');
|
|
const highScoreText = document.getElementById('highScore');
|
|
|
|
// Game variables
|
|
const gridSize = 20;
|
|
let snake = [{ x: 10, y: 10 }];
|
|
let food = generateFood();
|
|
let highScore = 0;
|
|
let direction = 'right';
|
|
let gameInterval;
|
|
let gameSpeedDelay = 200;
|
|
let gameStarted = false;
|
|
|
|
// Swipe variables
|
|
let touchStartX = 0;
|
|
let touchStartY = 0;
|
|
let touchEndX = 0;
|
|
let touchEndY = 0;
|
|
const minSwipeDistance = 30;
|
|
|
|
// Draw game
|
|
function draw() {
|
|
board.innerHTML = '';
|
|
drawSnake();
|
|
drawFood();
|
|
updateScore();
|
|
}
|
|
|
|
// Draw snake
|
|
function drawSnake() {
|
|
snake.forEach(segment => {
|
|
const snakeElement = document.createElement('div');
|
|
snakeElement.className = 'snake';
|
|
snakeElement.style.gridColumnStart = segment.x;
|
|
snakeElement.style.gridRowStart = segment.y;
|
|
board.appendChild(snakeElement);
|
|
});
|
|
}
|
|
|
|
// Draw food
|
|
function drawFood() {
|
|
if (!gameStarted) return;
|
|
const foodElement = document.createElement('div');
|
|
foodElement.className = 'food';
|
|
foodElement.style.gridColumnStart = food.x;
|
|
foodElement.style.gridRowStart = food.y;
|
|
board.appendChild(foodElement);
|
|
}
|
|
|
|
// Generate food
|
|
function generateFood() {
|
|
return {
|
|
x: Math.floor(Math.random() * gridSize) + 1,
|
|
y: Math.floor(Math.random() * gridSize) + 1
|
|
};
|
|
}
|
|
|
|
// Move snake
|
|
function move() {
|
|
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;
|
|
}
|
|
snake.unshift(head);
|
|
|
|
if (head.x === food.x && head.y === food.y) {
|
|
food = generateFood();
|
|
increaseSpeed();
|
|
resetInterval();
|
|
} else snake.pop();
|
|
}
|
|
|
|
// Start game
|
|
function startGame() {
|
|
if (gameStarted) return;
|
|
gameStarted = true;
|
|
instructionText.style.display = 'none';
|
|
logo.style.display = 'none';
|
|
gameInterval = setInterval(() => { move(); checkCollision(); draw(); }, gameSpeedDelay);
|
|
}
|
|
|
|
// Keyboard control
|
|
function handleKeyPress(e) {
|
|
if (!gameStarted && (e.code === 'Space' || e.key === ' ')) startGame();
|
|
if (e.key === 'ArrowUp' && direction !== 'down') direction = 'up';
|
|
if (e.key === 'ArrowDown' && direction !== 'up') direction = 'down';
|
|
if (e.key === 'ArrowLeft' && direction !== 'right') direction = 'left';
|
|
if (e.key === 'ArrowRight' && direction !== 'left') direction = 'right';
|
|
}
|
|
document.addEventListener('keydown', handleKeyPress);
|
|
|
|
// Swipe control
|
|
board.addEventListener('touchstart', e => {
|
|
const touch = e.touches[0];
|
|
touchStartX = touch.clientX;
|
|
touchStartY = touch.clientY;
|
|
});
|
|
board.addEventListener('touchend', e => {
|
|
const touch = e.changedTouches[0];
|
|
touchEndX = touch.clientX;
|
|
touchEndY = touch.clientY;
|
|
handleSwipe();
|
|
});
|
|
board.addEventListener('touchmove', e => e.preventDefault(), { passive: false });
|
|
|
|
function handleSwipe() {
|
|
const dx = touchEndX - touchStartX;
|
|
const dy = touchEndY - touchStartY;
|
|
if (Math.abs(dx) < minSwipeDistance && Math.abs(dy) < minSwipeDistance) return;
|
|
if (Math.abs(dx) > Math.abs(dy)) {
|
|
if (dx > 0 && direction !== 'left') direction = 'right';
|
|
else if (dx < 0 && direction !== 'right') direction = 'left';
|
|
} else {
|
|
if (dy > 0 && direction !== 'up') direction = 'down';
|
|
else if (dy < 0 && direction !== 'down') direction = 'up';
|
|
}
|
|
if (!gameStarted) startGame();
|
|
}
|
|
|
|
// Increase speed
|
|
function increaseSpeed() {
|
|
if (gameSpeedDelay > 150) gameSpeedDelay -= 5;
|
|
else if (gameSpeedDelay > 100) gameSpeedDelay -= 3;
|
|
else if (gameSpeedDelay > 50) gameSpeedDelay -= 2;
|
|
else if (gameSpeedDelay > 25) gameSpeedDelay -= 1;
|
|
}
|
|
|
|
function resetInterval() {
|
|
clearInterval(gameInterval);
|
|
gameInterval = setInterval(() => { move(); checkCollision(); draw(); }, gameSpeedDelay);
|
|
}
|
|
|
|
// Collision
|
|
function checkCollision() {
|
|
const head = snake[0];
|
|
if (head.x < 1 || head.x > gridSize || head.y < 1 || head.y > gridSize) resetGame();
|
|
for (let i = 1; i < snake.length; i++) if (head.x === snake[i].x && head.y === snake[i].y) resetGame();
|
|
}
|
|
|
|
// Reset game
|
|
function resetGame() {
|
|
updateHighScore();
|
|
stopGame();
|
|
snake = [{ x: 10, y: 10 }];
|
|
food = generateFood();
|
|
direction = 'right';
|
|
gameSpeedDelay = 200;
|
|
draw();
|
|
}
|
|
|
|
// Score
|
|
function updateScore() {
|
|
score.textContent = (snake.length - 1).toString().padStart(3, '0');
|
|
}
|
|
function stopGame() {
|
|
clearInterval(gameInterval);
|
|
gameStarted = false;
|
|
instructionText.style.display = 'block';
|
|
logo.style.display = 'block';
|
|
}
|
|
function updateHighScore() {
|
|
const currentScore = snake.length - 1;
|
|
if (currentScore > highScore) {
|
|
highScore = currentScore;
|
|
highScoreText.textContent = highScore.toString().padStart(3, '0');
|
|
}
|
|
highScoreText.style.display = 'block';
|
|
}
|