Гид по технологиям

Как создать игру «Змейка» на HTML, CSS и JavaScript

8 min read Учебник Обновлено 03 Jan 2026
Как создать игру Змейка на HTML/CSS/JS
Как создать игру Змейка на HTML/CSS/JS

Человек держит Game Boy

Введение

Игра «Змейка» — классическая учебная задача для практики программирования и решения задач. Проект подходит для знакомства с DOM, canvas‑рендерингом, обработкой событий и простыми игровыми циклами. В этой статье все шаги приведены так, чтобы вы могли сразу запустить игру локально и постепенно улучшать её.

Краткая терминология:

  • Canvas — элемент HTML для 2D‑рисования.
  • Сегмент — один «квадратик» змейки.
  • Дот (dot) — кусочек еды на поле.

Что потребуется

  • Любой текстовый редактор (VS Code, Atom, Sublime и т. п.).
  • Современный браузер (Chrome, Firefox, Edge).
  • Папка проекта с файлами index.html, styles.css, script.js.

Важно: все примеры кода можно вставлять в файлы с указанными именами и открывать index.html в браузере.

Основная идея реализации — кратко

  1. Создаём canvas 400×400 px и стилизуем страницу.
  2. В script.js инициализируем переменные: положение змейки, массив сегментов, длину, направление и массив еды.
  3. В цикле игры (gameLoop) обновляем позицию, рисуем сцену, генерируем еду и проверяем столкновения.
  4. На нажатия клавиш реагируем сменой направления движения.

Факты: canvas 400×400 px (рекомендация), размер сегмента 10 пикселей, интервал игрового цикла — 100 мс, максимум одновременно 10 точек еды (в примере).


Создание пользовательского интерфейса для canvas

Для отображения игрового поля используйте обычный HTML и CSS. Создайте базовую структуру и подключите стили.

  1. Создайте файл index.html.
  2. Откройте его в редакторе и вставьте базовую структуру:


  
    
    
    Snake Game
  
  

  
  1. Внутри body добавьте заголовок и canvas:

Snake Game

  1. В той же папке создайте файл styles.css. Пример простых стилей:
#game {
  width:400px;
  height:400px;
  margin:0 auto;
  background-color:#eee;
}
h2 {
  text-align:center;
  font-family:Arial;
  font-size:36px;
}
  1. Подключите стили в head:
  1. Откройте index.html в браузере, чтобы увидеть пустой canvas.

Пустой холст игры «Змейка»

Важно: в CSS и JavaScript размеры поля задаются в пикселях (px). При желании можно сделать адаптивный canvas, но в учебном примере фиксированный размер упрощает расчёты.

Отрисовка змейки

Змейка состоит из нескольких квадратных сегментов. На старте длина — один сегмент. Ниже — базовые шаги по отрисовке.

  1. В index.html подключите JavaScript внизу body:



  
  1. Создайте script.js и получите элемент canvas:
var canvas = document.getElementById("snake");
  1. Установите 2D‑контекст для рисования:
var canvas2d = canvas.getContext("2d");
  1. Инициализируйте переменные:
var gameEnded = false;
canvas.width = 400;
canvas.height = 400;
  1. Объявите массив сегментов и длину змейки:
var snakeSegments = [];
var snakeLength = 1;
  1. Начальные координаты головы змейки:
var snakeX = 0;
var snakeY = 0;
  1. Функция moveSnake добавляет текущие координаты в начало массива сегментов:
function moveSnake() {
  snakeSegments.unshift({ x: snakeX, y: snakeY });
}
  1. Функция drawSnake устанавливает цвет и рисует сегменты:
function drawSnake() {
  canvas2d.fillStyle = "black";
}
  1. Для каждого сегмента отрисуйте прямоугольник 10×10 px:
for (var i = 0; i < snakeSegments.length; i++) {
  canvas2d.fillRect(snakeSegments[i].x, snakeSegments[i].y, 10, 10);
}
  1. Создайте игровой цикл, выполняющийся каждые 100 мс:
function gameLoop() {
  moveSnake();
  drawSnake();
  // далее — генерация еды, проверка столкновений и повторы цикла
}
  1. Откройте index.html — вы должны увидеть змейку в начальной позиции.

Змейка в начальной позиции

Примечание: пока нет очистки холста и удаления лишних сегментов — змейка будет оставлять след.

Движение змейки

Добавьте логику смены направления при нажатии клавиш и обновления координат.

  1. В начале файла объявите направление (например, движение вправо):
var directionX = 10;
var directionY = 0;
  1. Добавьте обработчик нажатий клавиш:
document.onkeydown = function(event) {

};
  1. Внутри обработчика обновляйте направление в зависимости от кода клавиши:
switch (event.keyCode) {
  case 37: // Left arrow
    directionX = -10;
    directionY = 0;
    break;
  case 38: // Up arrow
    directionX = 0;
    directionY = -10;
    break;
  case 39: // Right arrow
    directionX = 10;
    directionY = 0;
    break;
  case 40: // Down arrow
    directionX = 0;
    directionY = 10;
    break;
}
  1. В функции moveSnake после unshift примените направление к координатам:
function moveSnake() {
  snakeSegments.unshift({ x: snakeX, y: snakeY });
  snakeX += directionX;
  snakeY += directionY;
}
  1. Убедитесь, что в drawSnake в начале очищается холст:
canvas2d.clearRect(0, 0, canvas.width, canvas.height);
  1. В moveSnake удаляйте лишние сегменты, чтобы длина массива соответствовала текущей длине змейки:
while (snakeSegments.length > snakeLength) {
  snakeSegments.pop();
}

После этого при нажатии стрелок сегмент будет перемещаться по полю, как одиночная «голова». Чтобы увидеть это в действии, откройте index.html и используйте стрелки.

Одиночный сегмент движется по полю

Совет: добавьте простую защиту от мгновенного разворота на 180° (например, блокируйте смену направления на противоположную), чтобы игрок не врезался сам в себя из‑за резкого ввода.

Добавление еды на поле

Еда — это точки, которые генерируются в случайных позициях. При съедании змейка увеличивает длину.

  1. Объявите массив dots для точек еды:
var dots = [];
  1. Создайте функцию spawnDots, которая добавляет случайные точки, поддерживая до 10 штук:
function spawnDots() {
  if(dots.length < 10) {
    var dotX = Math.floor(Math.random() * canvas.width);
    var dotY = Math.floor(Math.random() * canvas.height);
    dots.push({ x: dotX, y: dotY });
  }
}
  1. Отрисуйте точки красным цветом:
for (var i = 0; i < dots.length; i++) {
  canvas2d.fillStyle = "red";
  canvas2d.fillRect(dots[i].x, dots[i].y, 10, 10);
}
  1. Вызывайте spawnDots() в gameLoop, чтобы в кадрах появлялась еда:
function gameLoop() {
  moveSnake();
  drawSnake();
  spawnDots();
  if(!gameEnded) {
    setTimeout(gameLoop, 100);
  }
}
  1. Откройте страницу и убедитесь, что на поле появляются красные квадратики — еда.

Еда на игровом поле

Замечание: в текущей реализации координаты еды могут быть любыми пикселями, не обязательно кратными 10 — это влияет на точность столкновений. Ниже рассмотрим вариант выравнивания сетки.

Сделать генерацию еды и движения сеточной (опционально)

Лучше выравнивать координаты еды и стартовую позицию по сетке размера сегмента (10 px), тогда столкновения будут точными и предсказуемыми.

Пример генерации точки, выровненной по сетке:

var gridSize = 10; // размер сегмента в пикселях
var cols = canvas.width / gridSize;
var rows = canvas.height / gridSize;

function spawnDotsGrid() {
  if (dots.length < 10) {
    var dotX = Math.floor(Math.random() * cols) * gridSize;
    var dotY = Math.floor(Math.random() * rows) * gridSize;
    dots.push({ x: dotX, y: dotY });
  }
}

Используйте gridSize при вычислении направлений и проверках столкновений.

Как заставить змейку расти

При столкновении головы со «едой» увеличиваем snakeLength и удаляем точку из dots.

  1. Создаём функцию checkCollision:
function checkCollision() {
  for (var i = 0; i < dots.length; i++) {

  }
}
  1. Если координаты головы пересекаются с координатами точки (AABB проверка), увеличиваем длину и удаляем точку:
if (snakeX < dots[i].x + 10 &&
  snakeX + 10 > dots[i].x &&
  snakeY < dots[i].y + 10 &&
  snakeY + 10 > dots[i].y) {
    snakeLength++;
    dots.splice(i, 1);
}
  1. Вызывайте checkCollision() в gameLoop:
function gameLoop() {
  moveSnake();
  drawSnake();
  spawnDots();
  checkCollision();
  if(!gameEnded) {
    setTimeout(gameLoop, 100);
  }
}

После съедания еды длина змейки увеличится, так как в каждом кадре добавляется новая «голова», а удаление хвоста контролируется переменной snakeLength.

Финальная доска с едой и змейкой

Окончание игры

Игра должна завершаться, когда голова сталкивается со стеной или с собственным хвостом.

  1. Функция gameOver показывает уведомление и ставит флаг завершения игры:
function gameOver() {
  setTimeout(function() {
    alert("Game over!");
  }, 500);
  gameEnded = true
}
  1. В checkCollision проверьте выход за границы canvas:
if (snakeX < -10 ||
  snakeY < -10 ||
  snakeX > canvas.width+10 ||
  snakeY > canvas.height+10) {
    gameOver();
}
  1. Для проверки столкновения головы с хвостом пройдитесь по массиву сегментов (начиная с 1, пропуская голову на индексе 0):
for (var i = 1; i < snakeSegments.length; i++) {

}

if (snakeX === snakeSegments[i].x && snakeY === snakeSegments[i].y) {
  gameOver();
}
  1. Запустите игру и проверьте: при столкновении с стеной или хвостом появится alert «Game over!».

Окно «Игра окончена»

Совет: вместо alert можно отрисовывать сообщение на canvas и предлагать кнопку “Перезапустить”.

Улучшения и варианты развития

Ниже — список улучшений и альтернативных подходов, которыми можно воспользоваться после базовой реализации.

  1. Выравнивание по сетке (gridSize) для улучшенной предсказуемости столкновений.
  2. Плавное движение: интерполяция между клетками для анимации при меньшем шаге в пикселях.
  3. Работа с touch и мобильными жестами: добавить виртуальные кнопки управления или свайпы.
  4. Сложность: увеличивать скорость (уменьшать интервал gameLoop) с ростом длины или по таймеру.
  5. Использование requestAnimationFrame вместо setTimeout для более плавной и эффективной отрисовки.
  6. Сохранение рекорда в localStorage, табло лидеров.
  7. Добавление препятствий на поле, разных видов еды с бонусами/вредом.
  8. Перехват фокуса и пауза при потере окна (visibilitychange).

Важно: requestAnimationFrame даёт частоту отрисовки, но тогда нужно вычислять движение на базе прошедшего времени (deltaTime).

Частые ошибки и способы их устранения

  • Змейка «застревает» или дергается при быстром смене клавиш: блокируйте смену направления до следующего кадра.
  • Столкновения не срабатывают из‑за дробных координат: выровняйте координаты по сетке.
  • Еда появляется частично вне области видимости: генерируйте позиции валидно в диапазоне [0, canvas.width-gridSize].
  • Накладывающаяся еда на змейку: проверяйте при генерации, чтобы точка не появлялась на текущих сегментах.

Чек‑лист перед публикацией (роль‑ориентированный)

Разработчик:

  • Код не содержит глобальных конфликтующих переменных.
  • Обработчики клавиш не создают утечек памяти.
  • Реализация использует gridSize для предсказуемости.

Тестировщик:

  • Проверить движение по всем направлениям.
  • Проверить съедение еды и рост змейки.
  • Проверить завершение при столкновениях и выход за границы.
  • Проверить поведение при смене вкладки / потере фокуса.

Дизайнер:

  • Удобные размеры кнопок на мобильных устройствах.
  • Контраст цветов хорошо читается при цветовой слепоте.

Критерии приёмки

  • Игра запускается в современном браузере, canvas отображается корректно.
  • Змейка перемещается по нажатию стрелок (или виртуальных кнопок) и растёт при поедании еды.
  • Игра завершается при столкновении с границей или собственным хвостом.
  • После окончания игры игрок может перезапустить с начальных настроек.

Тестовые сценарии и критерии качества

  1. Начальная загрузка: canvas 400×400, одна «голова» в позиции (0,0).
  2. Движение: при последовательности нажатий змейка проходит путь без самоперекрытия (если не направлять сознательно).
  3. Поедание: при пересечении головы с клеткой еды длина увеличивается на 1.
  4. Столкновение с телом: при движении в себя — игра завершается.
  5. Столкновение со стеной: выход за границы завершает игру.
  6. Перезагрузка: стартовая кнопка или перезагрузка страницы возвращает стартовое состояние.

Шпаргалка по ключевым функциям (cheat sheet)

  • moveSnake() — смещает голову и управляет массивом сегментов.
  • drawSnake() — очищает холст и отрисовывает сегменты.
  • spawnDots() — создаёт еду.
  • checkCollision() — проверяет столкновения с едой, стенами и хвостом.
  • gameOver() — завершает игру и показывает сообщение.

Mermaid‑диаграмма — простое дерево принятия решения при коллизии:

flowchart TD
  A[Имеется ли столкновение?] -->|Нет| B[Продолжать игру]
  A -->|Со стеной| C[gameOver]
  A -->|С едой| D[Увеличить длину и удалить еду]
  A -->|С хвостом| C

Безопасность и конфиденциальность

Игра работает полностью в браузере; персональные данные не требуются. Если вы добавляете регистрацию или таблицу лидеров, храните минимально необходимую информацию и учитывайте требования локального законодательства о данных.

Сравнение подходов: canvas vs DOM

  • Canvas: эффективен при большом количестве объектов и частой перерисовке, но требует ручной отрисовки и управления состоянием.
  • DOM (div‑сетки): проще реализовать вначале (каждый сегмент — элемент), но при большом количестве элементов производительность падает.

Выбор зависит от целей: для учебного проекта canvas даёт полезный опыт с 2D‑графикой.

Ресурсы и дальнейшие шаги

  • Перевести координаты в систему gridSize для стабильности.
  • Добавить уровни, препятствия, дополнительные типы еды.
  • Поддержка мобильных жестов и touchcontrols.
  • Сохранение результатов в localStorage и создание табло лидеров.

Итог

Вы создали базовую игру «Змейка», покрыв ключевые моменты: интерфейс, отрисовка, движение, генерация еды, рост и завершение игры. Дальше можно улучшать UX, производительность и добавлять новые механики.

Важно: экспериментируйте с gridSize, скоростью и правилами — это отличная площадка для изучения JavaScript и игровых паттернов.

Краткое резюме

  • Canvas + JS — быстрый путь к интерактивной игре в браузере.
  • Grid‑подход упрощает логику столкновений.
  • Улучшайте игру постепенно: сначала корректность, затем UX и оптимизация.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как скачать полноразмерный аватар Discord
Руководство

Как скачать полноразмерный аватар Discord

CSV в Node.js: fs и fast-csv — чтение и запись
Node.js

CSV в Node.js: fs и fast-csv — чтение и запись

Как увеличить экран на ПК — все способы
Инструкции

Как увеличить экран на ПК — все способы

Как найти человека в WhatsApp — быстро и просто
Мессенджеры

Как найти человека в WhatsApp — быстро и просто

Подсказки формул в Excel — руководство
Excel

Подсказки формул в Excel — руководство

Папка «Если меня нет»: подготовьте экстренный профиль
Безопасность

Папка «Если меня нет»: подготовьте экстренный профиль