
Змейка – это динамическая игра, в которой игрок управляет последовательностью элементов, растущих при сборе еды. Вместо использования Canvas можно построить логику с помощью обычных HTML-элементов: поле игры создаётся в виде таблицы или набора div-блоков, которые обновляются через изменения их классов.
Основой механики является массив координат, описывающий тело змейки. При каждом шаге в массив добавляется новая голова, а последний элемент удаляется, если еда не съедена. Такой подход позволяет чётко контролировать длину и направление движения.
Управление реализуется через обработку событий keydown. Важно сразу исключить возможность разворота в противоположную сторону, чтобы змейка не врезалась сама в себя. Для хранения текущего направления удобно использовать переменную с одним из четырёх значений: up, down, left, right.
Система столкновений проверяется по двум условиям: выход за границы поля и пересечение головы с элементами массива тела. Для генерации еды можно выбирать случайную свободную клетку из доступных, избегая координат, занятых змеёй.
Создание HTML-структуры и настройка canvas

Для игры требуется минимальная разметка: контейнер с тегом
Пример:
<canvas id="game" width="400" height="400"></canvas>
Размеры указываются атрибутами width и height, так как изменение через CSS искажает координатную сетку. Для классической версии игры удобен квадрат 400×400 пикселей, который делится на клетки размером 20×20.
После вставки тега необходимо получить доступ к элементу через JavaScript с помощью document.getElementById("game"). Это позволит работать с методами отрисовки и задать сетку для движения змейки.
Инициализация игрового поля и переменных

Игровое поле можно реализовать с помощью обычной таблицы <table>. Размер задаётся константами, например: rows = 20, cols = 20. Каждая ячейка создаётся в цикле и сохраняется в двумерный массив для быстрого доступа по индексам.
Змейка представляется массивом координат, где первый элемент – голова. Пример начального значения: snake = [{x: 10, y: 10}]. Направление движения хранится в отдельной переменной, например direction = ‘right’.
Для генерации еды используется объект с координатами: food = {x: 5, y: 5}. Эти значения обновляются при каждом появлении новой еды в случайной ячейке, которая не пересекается с телом змейки.
Счёт очков можно хранить в переменной score = 0. Она увеличивается при каждом поедании еды и используется для отображения прогресса.
Таким образом, на старте игры инициализируются: массив ячеек поля, массив змейки, направление движения, координаты еды и счётчик очков. Эти структуры обеспечивают основу для дальнейшей логики игры.
Реализация движения змейки с помощью клавиатуры

Для управления достаточно отлавливать событие keydown. Клавиши со стрелками имеют коды: 37 (влево), 38 (вверх), 39 (вправо), 40 (вниз). Для надёжности следует использовать свойство event.key, так как оно более читаемо.
При изменении направления важно запретить мгновенный разворот в противоположную сторону, иначе змейка столкнётся сама с собой. Для этого можно хранить текущее направление и при обработке нового ввода проверять допустимость перехода.
Пример структуры с координатами и направлением:
let snake = [{x: 5, y: 5}];
let direction = "right";
document.addEventListener("keydown", function(e) {
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";
});
Каждое обновление игры голова змейки смещается на одну клетку в сторону, указанную переменной direction. Для этого вычисляется новое положение, а затем массив сегментов обновляется.
Сопоставление направлений со смещениями удобно хранить в объекте:
| Направление | Смещение по X | Смещение по Y |
|---|---|---|
| up | 0 | -1 |
| down | 0 | 1 |
| left | -1 | 0 |
| right | 1 | 0 |
Используя эту таблицу, можно вычислять координаты следующей клетки и добавлять её в начало массива змейки.
Добавление еды и проверка столкновений

Еда может быть представлена простым div-элементом с уникальным id. При каждом появлении еда должна генерироваться в случайных координатах, которые не совпадают с сегментами змейки.
- Создать функцию генерации случайных координат в пределах игрового поля.
- Проверить, что выбранная клетка не занята змейкой.
- Если клетка свободна – вставить div с классом «food» в DOM.
Пример функции для генерации еды:
function createFood(snake) {
let x, y;
do {
x = Math.floor(Math.random() * 20);
y = Math.floor(Math.random() * 20);
} while (snake.some(segment => segment.x === x && segment.y === y));
const food = document.createElement('div');
food.id = 'food';
food.style.gridRowStart = y + 1;
food.style.gridColumnStart = x + 1;
document.getElementById('board').appendChild(food);
return { x, y };
}
Чтобы проверить столкновение головы змейки с едой:
- Сравнить координаты головы и еды.
- Если совпали – удалить элемент еды из DOM.
- Увеличить массив змейки на один сегмент.
- Сгенерировать новую еду вызовом createFood().
Проверка столкновений со стенами и телом змейки:
- Голова выходит за границы игрового поля – игра завершается.
- Голова совпадает с любым сегментом тела – также конец игры.
function checkCollision(snake, boardSize) {
const head = snake[0];
if (
head.x < 0 || head.y < 0 ||
head.x >= boardSize || head.y >= boardSize
) return true;
for (let i = 1; i < snake.length; i++) {
if (head.x === snake[i].x && head.y === snake[i].y) {
return true;
}
}
return false;
}
Для хранения текущего счета создайте переменную score и увеличивайте её при каждом «съедании» еды. Например: score++;.
Чтобы отображать счет, заранее подготовьте элемент в разметке, например: <div id="score">0</div>. После изменения значения используйте document.getElementById("score").textContent = score;.
Для итогового результата при окончании игры добавьте отдельный блок, например: <div id="game-over"></div>. В момент остановки цикла присвойте ему текст: document.getElementById("game-over").textContent = "Игра окончена! Ваш результат: " + score;.
Организация игрового цикла с requestAnimationFrame
В игре Змейка игровой цикл управляет обновлением состояния змейки и отрисовкой элементов на экране. В JavaScript для этого используется requestAnimationFrame, обеспечивающий синхронизацию с частотой обновления экрана.
Для реализации цикла следует учитывать:
- Время между кадрами.
requestAnimationFrameвызывает функцию примерно 60 раз в секунду, поэтому необходимо контролировать скорость змейки отдельно, чтобы движение не было слишком быстрым. - Состояние игры. Каждый кадр нужно проверять текущее положение змейки, столкновения с границами и самопересечения.
- Обновление позиции. Логика движения змейки должна выполняться на основе последнего состояния и выбранного направления.
Пример структуры цикла:
- Определяем переменные
lastRenderTimeиgameSpeed. - Создаем функцию
main(currentTime), гдеcurrentTimeприходит отrequestAnimationFrame. - Вычисляем разницу времени:
const delta = (currentTime - lastRenderTime) / 1000; - Если
deltaпревышает1 / gameSpeed, вызываем функцииupdate()иdraw(), обновляемlastRenderTime. - Рекурсивно вызываем
requestAnimationFrame(main)для следующего кадра.
Рекомендации по оптимизации:
- Избегать тяжелых вычислений внутри цикла. Переменные для состояния змейки и еды лучше хранить в массивах и объектах.
- Разделять логику
updateиdraw, чтобы можно было менять частоту обновления и отрисовки независимо. - Использовать
deltaTimeдля точного контроля движения при нестабильной частоте кадров. - Следить за корректным отменением анимации при паузе или окончании игры через
cancelAnimationFrame.
Такой подход обеспечивает плавное движение змейки, стабильную скорость игры и позволяет легко внедрять дополнительные функции, например ускорение или замедление при сборе бонусов.
Вопрос-ответ:
Как правильно организовать игровое поле для змейки на JavaScript?
Игровое поле обычно создают с помощью HTML-элемента canvas. Важно задать размеры канваса и выбрать удобную сетку, чтобы змейка двигалась по клеткам. Для визуализации каждой клетки можно использовать прямоугольники, раскрашенные в разные цвета, а положение змейки хранить в массиве координат.
Как реализовать движение змейки по экрану?
Движение змейки создают с помощью обновления координат головы змейки в заданном направлении и смещения всех сегментов хвоста на позиции предыдущего сегмента. Часто используют функцию setInterval или requestAnimationFrame для регулярного обновления положения змейки, что позволяет контролировать скорость движения.
Каким образом можно обработать столкновение змейки с границами или с самой собой?
Для проверки столкновений нужно сопоставлять координаты головы змейки с координатами других сегментов и границ канваса. Если координаты совпадают, это сигнал к окончанию игры. Для границ достаточно сравнивать значения координат головы с размерами поля, а для хвоста — проверять каждый сегмент массива координат на совпадение с головой.
Как добавить «яблоки» для змейки и увеличить её длину при поедании?
Яблоки создают случайным образом внутри игрового поля, избегая клеток, занятых змейкой. Когда координаты головы совпадают с координатами яблока, змейка получает дополнительный сегмент, который добавляется в конец массива, а яблоко появляется в новой случайной позиции. Для этого удобно использовать генератор случайных чисел, привязанный к размеру сетки.
Какие способы есть для управления змейкой с клавиатуры?
Наиболее распространённый способ — использовать событие keydown для отслеживания нажатий стрелок или клавиш WASD. В обработчике события нужно менять направление движения змейки, проверяя, чтобы новая ось движения не была противоположна текущей, иначе змейка может столкнуться сама с собой мгновенно.
Как задать движение змейки в разные стороны с помощью клавиатуры?
Для управления змейкой обычно используют события клавиатуры. В JavaScript это делается через обработчик события ‘keydown’. Внутри него можно проверять, какая клавиша была нажата, используя свойство event.key или event.code, и в зависимости от этого менять направление движения. Например, при нажатии стрелки вверх меняется вертикальная скорость на отрицательное значение, при стрелке вниз — на положительное. Также важно предусмотреть запрет на разворот змейки на 180 градусов, чтобы она не «съела» сама себя за один ход.
Как правильно обновлять положение змейки и отображать её на экране?
Обновление положения змейки обычно реализуется через цикл, который повторяется с определённым интервалом. В JavaScript для этого используют функцию setInterval или requestAnimationFrame. В каждом цикле к массиву сегментов змейки добавляется новая координата головы, а последняя точка убирается, если змейка не съела еду. После обновления координат необходимо очистить холст (canvas) и отрисовать каждый сегмент змейки заново, используя методы fillRect или аналогичные. Такой подход позволяет плавно перемещать змейку и одновременно контролировать столкновения с границами и самой собой.
