<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Змейка</title>
<style>
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #1e1e1e;
font-family: sans-serif;
}
#gameCanvas {
border: 2px solid #444;
background: #000;
}
#score {
position: absolute;
top: 10px;
left: 10px;
color: #fff;
font-size: 18px;
}
#gameOver {
position: absolute;
display: none;
flex-direction: column;
align-items: center;
color: #fff;
font-size: 24px;
}
#restartBtn {
margin-top: 16px;
padding: 8px 16px;
font-size: 16px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
#restartBtn:hover {
background: #45a049;
}
</style>
</head>
<body>
<div id="score">Счёт: 0</div>
<canvas id="gameCanvas" width="600" height="400"></canvas>
<div id="gameOver">
<div>Игра окончена</div>
<button id="restartBtn">Начать заново</button>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const gameOverEl = document.getElementById('gameOver');
const restartBtn = document.getElementById('restartBtn');
const gridSize = 20;
const cellCountX = canvas.width / gridSize;
const cellCountY = canvas.height / gridSize;
let snake = [{ x: 10, y: 10 }];
let food = {};
let direction = { x: 0, y: 0 };
let nextDirection = { x: 0, y: 0 };
let score = 0;
let gameRunning = true;
function placeFood() {
food = {
x: Math.floor(Math.random() * cellCountX),
y: Math.floor(Math.random() * cellCountY)
};
// Избегаем генерации еды внутри змеи
if (snake.some(segment => segment.x === food.x && segment.y === food.y)) {
placeFood();
}
}
function resetGame() {
snake = [{ x: 10, y: 10 }];
direction = { x: 0, y: 0 };
nextDirection = { x: 0, y: 0 };
score = 0;
scoreEl.textContent = `Счёт: ${score}`;
placeFood();
gameOverEl.style.display = 'none';
gameRunning = true;
}
function moveSnake() {
if (!gameRunning) return;
// Фиксируем направление только после шага (предотвращаем 180° поворот)
direction = { ...nextDirection };
if (direction.x === 0 && direction.y === 0) return;
const head = { ...snake[0] };
head.x += direction.x;
head.y += direction.y;
// Проверка выхода за границы
if (head.x < 0 || head.x >= cellCountX || head.y < 0 || head.y >= cellCountY) {
endGame();
return;
}
// Проверка столкновения с собой
if (snake.some(segment => segment.x === head.x && segment.y === head.y)) {
endGame();
return;
}
snake.unshift(head);
// Проверка поедания еды
if (head.x === food.x && head.y === food.y) {
score += 10;
scoreEl.textContent = `Счёт: ${score}`;
placeFood();
} else {
snake.pop(); // Удаляем хвост, если не съели
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Змея
snake.forEach((segment, index) => {
ctx.fillStyle = index === 0 ? '#4CAF50' : '#8BC34A';
ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize);
ctx.strokeStyle = '#2E7D32';
ctx.strokeRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize);
});
// Еда
ctx.fillStyle = '#FF5252';
ctx.beginPath();
ctx.arc(
(food.x + 0.5) * gridSize,
(food.y + 0.5) * gridSize,
gridSize / 2 - 2,
0,
Math.PI * 2
);
ctx.fill();
}
function gameLoop() {
moveSnake();
draw();
if (gameRunning) {
setTimeout(() => requestAnimationFrame(gameLoop), 120); // ~8.3 FPS → можно регулировать
}
}
function endGame() {
gameRunning = false;
gameOverEl.style.display = 'flex';
}
// Управление
window.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowUp': if (direction.y === 0) nextDirection = { x: 0, y: -1 }; break;
case 'ArrowDown': if (direction.y === 0) nextDirection = { x: 0, y: 1 }; break;
case 'ArrowLeft': if (direction.x === 0) nextDirection = { x: -1, y: 0 }; break;
case 'ArrowRight': if (direction.x === 0) nextDirection = { x: 1, y: 0 }; break;
case 'w': case 'W': if (direction.y === 0) nextDirection = { x: 0, y: -1 }; break;
case 's': case 'S': if (direction.y === 0) nextDirection = { x: 0, y: 1 }; break;
case 'a': case 'A': if (direction.x === 0) nextDirection = { x: -1, y: 0 }; break;
case 'd': case 'D': if (direction.x === 0) nextDirection = { x: 1, y: 0 }; break;
}
});
restartBtn.addEventListener('click', resetGame);
// Инициализация
placeFood();
gameLoop();
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Змейка</title>
<style>
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #1e1e1e;
font-family: sans-serif;
}
#gameCanvas {
border: 2px solid #444;
background: #000;
}
#score {
position: absolute;
top: 10px;
left: 10px;
color: #fff;
font-size: 18px;
}
#gameOver {
position: absolute;
display: none;
flex-direction: column;
align-items: center;
color: #fff;
font-size: 24px;
}
#restartBtn {
margin-top: 16px;
padding: 8px 16px;
font-size: 16px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
#restartBtn:hover {
background: #45a049;
}
</style>
</head>
<body>
<div id="score">Счёт: 0</div>
<canvas id="gameCanvas" width="600" height="400"></canvas>
<div id="gameOver">
<div>Игра окончена</div>
<button id="restartBtn">Начать заново</button>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const gameOverEl = document.getElementById('gameOver');
const restartBtn = document.getElementById('restartBtn');
const gridSize = 20;
const cellCountX = canvas.width / gridSize;
const cellCountY = canvas.height / gridSize;
let snake = [{ x: 10, y: 10 }];
let food = {};
let direction = { x: 0, y: 0 };
let nextDirection = { x: 0, y: 0 };
let score = 0;
let gameRunning = true;
function placeFood() {
food = {
x: Math.floor(Math.random() * cellCountX),
y: Math.floor(Math.random() * cellCountY)
};
// Избегаем генерации еды внутри змеи
if (snake.some(segment => segment.x === food.x && segment.y === food.y)) {
placeFood();
}
}
function resetGame() {
snake = [{ x: 10, y: 10 }];
direction = { x: 0, y: 0 };
nextDirection = { x: 0, y: 0 };
score = 0;
scoreEl.textContent = `Счёт: ${score}`;
placeFood();
gameOverEl.style.display = 'none';
gameRunning = true;
}
function moveSnake() {
if (!gameRunning) return;
// Фиксируем направление только после шага (предотвращаем 180° поворот)
direction = { ...nextDirection };
if (direction.x === 0 && direction.y === 0) return;
const head = { ...snake[0] };
head.x += direction.x;
head.y += direction.y;
// Проверка выхода за границы
if (head.x < 0 || head.x >= cellCountX || head.y < 0 || head.y >= cellCountY) {
endGame();
return;
}
// Проверка столкновения с собой
if (snake.some(segment => segment.x === head.x && segment.y === head.y)) {
endGame();
return;
}
snake.unshift(head);
// Проверка поедания еды
if (head.x === food.x && head.y === food.y) {
score += 10;
scoreEl.textContent = `Счёт: ${score}`;
placeFood();
} else {
snake.pop(); // Удаляем хвост, если не съели
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Змея
snake.forEach((segment, index) => {
ctx.fillStyle = index === 0 ? '#4CAF50' : '#8BC34A';
ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize);
ctx.strokeStyle = '#2E7D32';
ctx.strokeRect(segment.x * gridSize, segment.y * gridSize, gridSize, gridSize);
});
// Еда
ctx.fillStyle = '#FF5252';
ctx.beginPath();
ctx.arc(
(food.x + 0.5) * gridSize,
(food.y + 0.5) * gridSize,
gridSize / 2 - 2,
0,
Math.PI * 2
);
ctx.fill();
}
function gameLoop() {
moveSnake();
draw();
if (gameRunning) {
setTimeout(() => requestAnimationFrame(gameLoop), 120); // ~8.3 FPS → можно регулировать
}
}
function endGame() {
gameRunning = false;
gameOverEl.style.display = 'flex';
}
// Управление
window.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowUp': if (direction.y === 0) nextDirection = { x: 0, y: -1 }; break;
case 'ArrowDown': if (direction.y === 0) nextDirection = { x: 0, y: 1 }; break;
case 'ArrowLeft': if (direction.x === 0) nextDirection = { x: -1, y: 0 }; break;
case 'ArrowRight': if (direction.x === 0) nextDirection = { x: 1, y: 0 }; break;
case 'w': case 'W': if (direction.y === 0) nextDirection = { x: 0, y: -1 }; break;
case 's': case 'S': if (direction.y === 0) nextDirection = { x: 0, y: 1 }; break;
case 'a': case 'A': if (direction.x === 0) nextDirection = { x: -1, y: 0 }; break;
case 'd': case 'D': if (direction.x === 0) nextDirection = { x: 1, y: 0 }; break;
}
});
restartBtn.addEventListener('click', resetGame);
// Инициализация
placeFood();
gameLoop();
</script>
</body>
</html>