blackeeee's picture
по принципу mcp разбей
cf29d38 verified
```javascript
document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const startBtn = document.getElementById('startBtn');
const resetBtn = document.getElementById('resetBtn');
const upBtn = document.getElementById('upBtn');
const downBtn = document.getElementById('downBtn');
const leftBtn = document.getElementById('leftBtn');
const rightBtn = document.getElementById('rightBtn');
// Game variables
let snake = [];
let food = {};
let direction = 'right';
let nextDirection = 'right';
let gameSpeed = 150;
let score = 0;
let gameInterval;
let gameRunning = false;
const gridSize = 20;
const tileCount = canvas.width / gridSize;
// Initialize game
function initGame() {
snake = [];
for (let i = 3; i >= 0; i--) {
snake.push({ x: i * gridSize, y: 0 });
}
generateFood();
score = 0;
scoreElement.textContent = score;
direction = 'right';
nextDirection = 'right';
if (gameRunning) {
clearInterval(gameInterval);
gameInterval = setInterval(gameLoop, gameSpeed);
}
drawGame();
}
// Generate food at random position
function generateFood() {
food = {
x: Math.floor(Math.random() * tileCount) * gridSize,
y: Math.floor(Math.random() * tileCount) * gridSize
};
// Make sure food doesn't spawn on snake
for (let segment of snake) {
if (segment.x === food.x && segment.y === food.y) {
return generateFood();
}
}
}
// Main game loop
function gameLoop() {
moveSnake();
checkCollision();
drawGame();
}
// Move the snake
function moveSnake() {
direction = nextDirection;
// Calculate new head position
const head = { x: snake[0].x, y: snake[0].y };
switch (direction) {
case 'up':
head.y -= gridSize;
break;
case 'down':
head.y += gridSize;
break;
case 'left':
head.x -= gridSize;
break;
case 'right':
head.x += gridSize;
break;
}
// Add new head
snake.unshift(head);
// Check if snake ate food
if (head.x === food.x && head.y === food.y) {
score++;
scoreElement.textContent = score;
generateFood();
// Increase speed every 5 points
if (score % 5 === 0) {
gameSpeed = Math.max(50, gameSpeed - 10);
clearInterval(gameInterval);
gameInterval = setInterval(gameLoop, gameSpeed);
}
} else {
// Remove tail if no food eaten
snake.pop();
}
}
// Check for collisions
function checkCollision() {
const head = snake[0];
// Wall collision
if (
head.x < 0 || head.x >= canvas.width ||
head.y < 0 || head.y >= canvas.height
) {
gameOver();
}
// Self collision
for (let i = 1; i < snake.length; i++) {
if (head.x === snake[i].x && head.y === snake[i].y) {
gameOver();
}
}
}
// Game over
function gameOver() {
clearInterval(gameInterval);
gameRunning = false;
startBtn.textContent = 'Restart Game';
alert(`Game Over! Your score: ${score}`);
}
// Draw game elements
function drawGame() {
// Clear canvas
ctx.fillStyle = '#111827';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw snake
snake.forEach((segment, index) => {
const gradient = ctx.createLinearGradient(segment.x, segment.y, segment.x + gridSize, segment.y + gridSize);
if (index === 0) {
// Head - brighter green
gradient.addColorStop(0, '#4ade80');
gradient.addColorStop(1, '#22c55e');
} else {
// Body - darker green
gradient.addColorStop(0, '#16a34a');
gradient.addColorStop(1, '#15803d');
}
ctx.fillStyle = gradient;
ctx.fillRect(segment.x, segment.y, gridSize - 1, gridSize - 1);
// Add eyes to head
if (index === 0) {
ctx.fillStyle = 'white';
// Right eye
if (direction === 'right') {
ctx.fillRect(segment.x + 12, segment.y + 5, 3, 3);
ctx.fillRect(segment.x + 12, segment.y + 12, 3, 3);
}
// Left eye
else if (direction === 'left') {
ctx.fillRect(segment.x + 5, segment.y + 5, 3, 3);
ctx.fillRect(segment.x + 5, segment.y + 12, 3, 3);
}
// Up eye
else if (direction === 'up') {
ctx.fillRect(segment.x + 5, segment.y + 5, 3, 3);
ctx.fillRect(segment.x + 12, segment.y + 5, 3, 3);
}
// Down eye
else if (direction === 'down') {
ctx.fillRect(segment.x + 5, segment.y + 12, 3, 3);
ctx.fillRect(segment.x + 12, segment.y + 12, 3, 3);
}
}
});
// Draw food
const foodGradient = ctx.createRadialGradient(
food.x + gridSize/2, food.y + gridSize/2, 0,
food.x + gridSize/2, food.y + gridSize/2, gridSize/2
);
foodGradient.addColorStop(0, '#ef4444');
foodGradient.addColorStop(1, '#dc2626');
ctx.fillStyle = foodGradient;
ctx.beginPath();
ctx.arc(food.x + gridSize/2, food.y + gridSize/2, gridSize/2 - 1, 0, Math.PI * 2);
ctx.fill();
}
// Event listeners
startBtn.addEventListener('click', () => {
if (!gameRunning) {
gameRunning = true;
startBtn.textContent = 'Pause';
initGame();
gameInterval = setInterval(gameLoop, gameSpeed);
} else {
gameRunning = false;
clearInterval(gameInterval);
startBtn.textContent = 'Resume';
}
});
resetBtn.addEventListener('click', () => {
clearInterval(gameInterval);
gameRunning = false;
startBtn.textContent = 'Start Game';
initGame();
});
// Keyboard controls
document.addEventListener('keydown', (e) => {
switch (e.key) {
case 'ArrowUp':
if (direction !== 'down') nextDirection = 'up';
break;
case 'ArrowDown':
if (direction !== 'up') nextDirection = 'down';
break;
case 'ArrowLeft':
if (direction !== 'right') nextDirection = 'left';
break;
case 'ArrowRight':
if (direction !== 'left') nextDirection = 'right';
break;
}
});
// Touch controls
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 game state
initGame();
});
```