Змейка

Начнём с небольшой предыстории: пару недель назад я ждал друга в кафе. Как обычно, он опаздывал примерно минут на сорок. Ноутбук с собой, интернет есть, а игр нет — чисто рабочая машина, ничего лишнего, хотя нужно будет что-то скачать, чтобы играть на работе xd. От скуки я открыл браузер и набрал в поиске «змейка». Google выдал свою фирменную змейку прямо в результатах поиска.

Я кликнул, и пошла игра. Потом прошло пять минут, десять, пятнадцать, и я не мог оторваться, так как немного азартный и, пока не выиграю, не захочу заканчивать. После многих поражений, примерно на двадцать пятой минуте игры, я поймал себя на мысли: а почему яблоко всегда жертва и почему вообще змейка — наш главный герой?

Друг пришёл на тридцать пятой минуте. Я закрыл ноутбук, но мысль засела. И тем же вечером я уже начал писать код: вот поле, вот красное яблоко, вот змейка, вот ещё одна, и все они пытаются съесть яблоко.

Так моё желание доказать, что яблоко не просто ждун, а тоже личность, пошло дальше, и я решил написать минимально простую игру: просто посмотреть логику и подумать, может, поменять правила или как-то усложнить игру.

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

Как устроена обычная змейка

Начнём, думаю, с классики — как устроена обычная змейка и с чего все началось. Если говорить кратко про историю то, первая версия появилась аж в 1976 году под названием Blockade — её запилили ребята из Gremlin Industries для игровых автоматов. И самое удивительное, что для меня стало новостью: там никаких яблок вообще не было, и змея была не одна и вообще не росла.

Смысл игры был таким, что два игрока управляли змеями, которые оставляли за собой стену, и условием победы было просто загнать соперника в тупик. Если вспоминать аналоги, то мне сразу же напомнили эту игру события из фильма и одноимённой игры Tron Light Cycles. В конце концов всё оказалось ещё проще, чем в той игре, которую все знают: никакой еды и очков, просто стены и змейки. Потом, в 1978-м, игра перебралась на Atari 2600 под названием Surround — там уже добавили цвета и разные режимы, но суть та же: стены и тупики.

А настоящий бум случился в 1997-м, когда Nokia взяла и предустановила Snake на свой 6110, и здесь понеслось — сотни миллионов телефонов, и змейка стала народной игрой, в которую рубились вообще все — от школьников до банкиров. В 2013-м Nokia переродилась под Microsoft, игру переписали под смартфоны, но та самая чёрно-белая версия уже навсегда в истории как символ мобильных игр девяностых (статья, в которой хорошо прописана история).

Blockade
Blockade

Теперь разберём, как работает классическая змейка. В этой игре простое поле, которое поделено на клетки, где в каждом кадре голова сдвигается в текущем направлении, новый сегмент добавляется в начало массива, а последний удаляется. Если змея съела яблоко, последний сегмент не удаляется, и змея растёт.

let head = { x: snake[0].x + dx, y: snake[0].y + dy };
snake.unshift(head);
if (!ateApple) snake.pop();

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

Если подумать, «Змейка» — очень понятная и простая игра, которая стала мировым феноменом благодаря своей универсальной доступности в те годы и увлекательному геймплею. Будучи предустановленной на миллионах легендарных телефонов Nokia, она предложила людям простой способ скоротать время и превратила мобильный телефон из аппарата для звонков в персональное игровое устройство, что было новинкой для того времени.

Как я перевернул правила

Первое, что я сделал, — поменял роли. Игрок управляет не змеёй, а яблоком. Цель — не собрать очки, а просто выжить как можно дольше. Счёт растёт сам по себе, каждое мгновение жизни — уже победа.

Второе — змеи больше не растут. Они появляются из-за краёв поля, проходят сквозь экран и исчезают с другой стороны, если игрок сумел от них уйти. Никакого поедания, никакого увеличения — только преследование. Вот тут, кстати, я думаю, можно поразмышлять, т. к. если, например, игра будет начинаться с маленьких змей, а потом, чем больше у тебя будет очков, тем больше будут становиться змейки (не пробовал, но эта идея пришла уже при написании статьи).

Третье — змеи бывают разные. Почти как пелось в песне: чёрные, белые, красные. Ладно, тут обычные зелёные, жёлтые и красные, как светофор. И это не просто внешний вид, а различия в их поведении в игре. Я хотел, чтобы игрок постоянно адаптировался, и поэтому их три вида, а появляются они случайным образом (почти). Так родились три типа:

Зелёные 
Зелёные 

Зелёные — обычные линейные крипы, которые идут прямо по линии без поворотов или каких-нибудь усложнений. Главное только то, что они ходят поочерёдно: то по горизонтали, то по вертикали.

Жёлтые
Жёлтые

Жёлтые — это змеи настроения, как я их называю, т. к. они быстрые и в любой момент могут поменять направление. (Примечание: поворот каждые десять ходов в сторону игрока. Пока оставил так, но, может, лучше поставить рандом.)

Красные 
Красные 

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

Четвёртое — сложность самой игры. Здесь были проблемы: баланс с нуля всегда сложно придумать, и поэтому его нужно будет, скорее всего, менять. Сейчас змеи появляются по таймерам, и чем дольше живёшь, тем короче становятся интервалы между спавнами. Тем самым на экране просто становится больше змей, и выжить почти невозможно.

Структура проекта

Я решил не сваливать всё в один файл, а разбить проект на модули. А так как проект простой, можно было и в один, но это некрасиво. Никаких сборщиков, никаких import и export — просто четыре файла, которые подключаются в правильном порядке через теги <script>. Открываешь index.html — и всё работает.

Вот как выглядит структура:

reverse-snake/
├── index.html
├── style.css
├── snake.js
├── renderer.js
└── game.js

Как игра работает внутри

Я решил не мудрить с архитектурой и написал всё на классах. Как обычно, и в прошлых статьях, я не использую никаких фреймворков, сборщиков или готовых решений из интернета. Главное, чтобы я мог открывать веб-программу и спокойно поиграть.

Теперь пойдём по классам. Например, класс Snake отвечает за одну змею. Он хранит массив сегментов тела, текущее направление, тип и коэффициент скорости. Главный метод update() получает позицию игрока и решает, куда двигаться дальше. Логика разная для каждого типа:

if (this.type === 'yellow' && this.state === 'normal' && this.timer === 10) {
    this.state = 'turned';
    if (this.dx !== 0) {
        this.dx = 0; 
        this.dy = player.y > head.y ? 1 : -1;
    } else {
        this.dy = 0; 
        this.dx = player.x > head.x ? 1 : -1;
    }
}

Класс Renderer занимается отрисовкой и ничем больше, использует только fillRect() и никаких спрайтов. Сетка рисуется как шахматная доска: чётные клетки темнее, нечётные светлее. Змеи отрисовываются как квадраты с внутренней текстурой и каждой змеи свой внешний вид: сначала внешний цвет, потом тёмный прямоугольник внутри, потом два чёрных квадратика-глаза у головы, чтобы у человека появлялось чувство антропоморфизма. Такое же действие делаем с яблоком, которое состоит из восьми пикселей на клетку: красное тело, белый блик, коричневый черешок и зелёный листик.

Класс Game управляет всем: запускает игровой цикл, обрабатывает коллизии, считает очки, спавнит змей по таймерам. Отдельно я вынес логику интервалов спавна в метод updateSpawnTimers(), который пересчитывает частоту появления змей в зависимости от текущего счёта.

Разделение на три файла (snake.js, renderer.js, game.js) спасло меня от хаоса. Когда жёлтая змея странно поворачивала, я знал, что копать нужно в Snake. Когда пиксели съезжали — проблема была в Renderer. Когда интервалы спавна работали не по плану — в Game. И так можно перечислять до бесконечности.

Адаптация под телефоны

Я люблю, когда проект можно открыть с любого устройства — и на компе, и на телефоне. Но с телефонами всегда морока. А, т. к. многие смотрят с телефона, то лучше придумать решение этих проблем.

С клавиатурой всё просто: её нет — значит, сделаем свою. Я добавил четыре кнопки-стрелки прямо на экране, под игровым полем. Они расположены крестом: верх, низ, лево, право. Выглядят как обычные серые квадраты с треугольниками внутри, ничего лишнего. На компе эти кнопки спрятаны, они появляются только на узких экранах, где ширина меньше 768 пикселей.

С размером экрана было сложнее всего, т. к. я привык, что на десктопе сетка 24×24 клетки смотрится нормально, но на телефоне она превращается в мелкую мозаику — пальцем не попасть, глаза сломаешь. Поэтому я сделал так, чтобы игра сама подстраивалась под ширину экрана. Если экран узкий, как у телефона, сетка становится 20×20 клеток — каждая клетка крупнее, и играть удобнее. Если планшет — 22×22. А если нормальный монитор — классические 24×24.

Ещё одна фишка — пауза. На компе я, как и обычно в играх, нажимаю Esc и спокойно ставлю игру на паузу, но вот здесь и появляется проблема, на телефоне Escape просто нет. Сначала аналогично мобильным играм, я хотел сделать отдельную кнопку паузы, но потом подумал и нашёл в интернете решение: а что, если просто встряхнуть телефон? Оказалось, в браузере есть событие devicemotion — оно считывает показания акселерометра. Я беру ускорение по трём осям, считаю общую величину, и если она больше 25 (это значит, что телефон хорошо тряхнули), игра встаёт на паузу. Работает как магия: тряхнул — меню вылезло. Интересное решение, которое нашёл в интернете. До этого проекта не знал, что так можно.

const magnitude = Math.sqrt(
    acceleration.x ** 2 + 
    acceleration.y ** 2 + 
    acceleration.z ** 2
);
if (magnitude > 25) pauseGame();

Балансировка и тестирование

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

Решение нашлось не сразу, но благодаря методу проб и ошибок. Я ввёл лимиты на максимальное количество змей каждого типа: не больше шести зелёных, пяти жёлтых и трёх красных, затем подогнал интервалы спавна под разные этапы игры, чтобы чем дольше ты играешь, тем была сложнее игра. Первые пятьдесят очков — расслабленный режим, только зелёные, к ста двадцати очкам появляются жёлтые и уже к двумстам пятидесяти — красные не отстают, и зелёные сыплются каждые восемнадцать ходов.

Итог

Могу сказать одно: это было неожиданно весело, я всего лишь хотел убить время в кафе, а в итоге получил великолепную идею, которую я смог реализовать и поиграть. Яблоко убегает, змеи наступают, счёт тикает — всё, как я задумал, и больше считаю, что добавлять ничего не надо.

Моё мнение о результате и размышления

Я доволен результатом, проект напомнил мне, что не всегда нужны сложные технологии, чтобы сделать что-то интересное. Иногда достаточно перевернуть старую идею с ног на голову — и получить новую игру.

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

Если же возвращаться к «Обратной змейке», проект мне понравился, идея простая, но цепляет. Реализация вышла минималистичной и стильной, как я и хотел. Но, конечно, есть что улучшить, хотя ничего критичного я пока не вижу.

Код проекта находится здесь, поиграть в мою версию «Змейки» можно здесь.

P.S. Если у вас есть идеи по улучшению, вы нашли баг или просто хотите похвастаться своим рекордом — пишите в комментариях.

© 2026 ООО «МТ ФИНАНС»

Комментарии (27)


  1. razvivausI_flag_I
    16.06.2026 13:42

    Идея и вправду оригинальная, как по мне. Поиграл с телефона. Рекорд 208. На телефоне иногда попадал не на кнопки управления. В целом играл на инстинктах и просто кликал. Конечно, и здесь можно натренироваться, но все же хардкор из-за постоянной генерации змей, маленького пространства самого поля и его ещё большего уменьшения из-за красных змей присутствует


    1. Laborant_Code Автор
      16.06.2026 13:42

      Спасибо за отзыв! И отдельный респект за то, что не просто прошли мимо, а поиграли и даже написали свой рекорд — 208 очков.

      Вы точно подметили ту проблему, которую я и сам заметил, — это баланс. Сейчас на 200-300+ очках баланс уходит в перекос: змей слишком много, а высокая скорость и маленькое поле почти не оставляют шансов на бесконечную игру, как это принято в подобных жанрах.

      Пока думаю, как можно улучшить или сбалансировать хардкор и саму игру, чтобы сохранить гармонию, поэтому, если есть идеи, рад буду услышать, может даже добавлю со временем.


      1. Owyn
        16.06.2026 13:42

        Поиграл с ПК-лисы:

        • яблоко при движении мерцает будто пытается убивать вас эпилепсией

        • куча змей которые по ощущениям движутся просто хаотично (если б они появлялись постепенной усложняя игру со временем - я б ещё понял)

        • всё довольно быстро происходит, по ощущениям куда быстрее классической змейки (и яблоко будто скользит по льду - моглиб хоть ноги ему приделать :-) )


  1. danilovmy
    16.06.2026 13:42

    Меня съела зеленая змея. Но вайб все равно от pac-man. Особенно когда яблоко начнёт собирать жемчужины....


    1. Laborant_Code Автор
      16.06.2026 13:42

      Спасибо за отзыв! Но если так подумать, смысл Pac-Man как раз в жемчужинах, а тут скорее надо выживать, как в Galaga только без уничтожений своих противников.


  1. gerbert_MX
    16.06.2026 13:42

    прикольно

    мой рекорд, я хз как автор на скрине за 600 ушел
    мой рекорд, я хз как автор на скрине за 600 ушел

    не хватает только регулировки скорости (и что бы результат высчитывался как скорость*время, а не просто время) и колизий меж змейками а то за 300 уже начинается каша когда может быть три вида змеек в одной клетке и если "не повезет" с генерацией то никакая ловкость пальцев не поможет так как змейки могут создавать закрытые обьемы, проходя свозь друг друга


    1. Laborant_Code Автор
      16.06.2026 13:42

      Вот, как и писал раньше, скорость и баланс появления надо продумать. А про рекорд 645 — это мастерство, которое не пропьешь (xd, я даже не заметил, что он был на скрине). Это, скорее всего, просто до усложнения появления был, а потом уже стало сложно и до 400+ очков дойти.

      Спасибо за ваше мнение!


    1. jouilk23
      16.06.2026 13:42

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


  1. iShrimp
    16.06.2026 13:42

    Эту игру можно улучшать и модифицировать бесконечно :)

    Змейка в 3D? - уже где-то было...

    Змейка на фрактале (ковре Серпинского)? Поле с дефектами.

    Змейка на сфере? Поле без границ, но конечной площади. Две параллельно идущие змейки обязательно пересекутся.

    Змейка на гиперболической плоскости (как в HyperRogue)? Места предостаточно. Параллельные прямые расходятся. Замучаешься искать яблоко. Зато хвост не будет мешать.

    Змейка, поворачивающая только в одну сторону? Или поочередно влево-вправо, с управлением одной кнопкой типа Snek Left в Fancade.

    Змейка, постоянно растущая, укорачивающаяся при съедании яблока?

    Змейка с квантовой механикой и суперпозицией кучи состояний? Почти как квантовые шахматы, только змейка.


    1. evgenstf
      16.06.2026 13:42

      Еще можно сделать игру, где ты типа грибок, и прыгаешь на супер Марио


      1. Laborant_Code Автор
        16.06.2026 13:42

        Тогда скорее Боузер и пытаешь похитить принцессу, а не спасти, как марио


  1. Metotron0
    16.06.2026 13:42

    Не честно, что змеи проходят друг сквозь друга. А ещё странно, что игрок появляется неподвижным, но потом нельзя остановиться.


    1. Laborant_Code Автор
      16.06.2026 13:42

      Про не неподвижность, скорее как в оригинале ты же вначале стоишь на месте, а потом нельзя остановиться. А про змей посмотрю, что можно сделать


      1. Sfekss
        16.06.2026 13:42

        В оригинале скорость увеличивается пропорционально съеденым вкусняшкам. Тут старт сразу с реактивной скорости, что добавляет сложности на старте.

        Какое среднее время игры? Начинается сразу с хардкора, 10 или 20 секунд? Вряд ли будет прям очень сильно затягивать, нужно больше времени для фиксации.


  1. Wesha
    16.06.2026 13:42

    Яблоко б на лягушку заменили, а то яблоко, которое само по себе ездит...


    1. Laborant_Code Автор
      16.06.2026 13:42

      Если рассуждать со стороны логики, то вы правы, но тогда пропадает шарм игры змейка, как будто


  1. san4ez_gig
    16.06.2026 13:42

    Прикольно, довольно затягивает. Я бы сделал кнопки на телефоне побольше и добавил коллизию между змеями


  1. alexs963
    16.06.2026 13:42

    ИГРА ОКОНЧЕНА

    Вас съела жёлтой змея

    Время жизни: 365


  1. Deosis
    16.06.2026 13:42

    Описание напоминает жанр Bullet Hell: надо уворачиваться от разных видов снарядов, заполняющих большую часть поля.


  1. sogonov
    16.06.2026 13:42

    Идея классная, можно по мотивам Марио добавить какие-то ГМО появляющиеся на пути яблока, чтобы оно на время могло выживать от одного укуса, или крушить змей собой. Однозначно добавит экшена)


    1. Laborant_Code Автор
      16.06.2026 13:42

      Хорошая идея, мне нравится, но надо подумать, что будет канонично — чтобы яблоко съело что-то и повысило себе защиту от змей.


  1. manyakRus
    16.06.2026 13:42

    а где кнопка остановиться на месте ?
    ато как бешенный принтер гоняет туда сюда


  1. teleomoon
    16.06.2026 13:42

    Сделал поле в два раза больше и сразу стало интересно играть.


  1. jouilk23
    16.06.2026 13:42

    Очередное переизобретение пакмана, только без лабиринта и возможности съесть привидений

    Зато на чистом джс, это мы уважаем


  1. Yarus23
    16.06.2026 13:42

    плюс минус 200 и все. хорошо бы чтобы дальше продолжать играть а) выкидывать на поле что то - жизни там например или невидимость б) например уровни - 200 шт от легких к сложным. и вконце каждого десятого уровня например босс.


  1. qondeeter
    16.06.2026 13:42

    Почему нет игры, где ты типо грибок, и ты прыгаешь на супер-Марио?


    1. Metotron0
      16.06.2026 13:42

      Тогда уж убегаешь от него, ведь грибы не прыгают.