惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Recorded Future
Recorded Future
Recent Announcements
Recent Announcements
Microsoft Azure Blog
Microsoft Azure Blog
The Register - Security
The Register - Security
N
Netflix TechBlog - Medium
GbyAI
GbyAI
E
Exploit-DB.com RSS Feed
Blog — PlanetScale
Blog — PlanetScale
阮一峰的网络日志
阮一峰的网络日志
L
LangChain Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Vercel News
Vercel News
博客园 - 三生石上(FineUI控件)
Microsoft Security Blog
Microsoft Security Blog
IT之家
IT之家
罗磊的独立博客
M
MIT News - Artificial intelligence
P
Proofpoint News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
N
News and Events Feed by Topic
O
OpenAI News
大猫的无限游戏
大猫的无限游戏
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
H
Hacker News: Front Page
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
Forbes - Security
Forbes - Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Hugging Face - Blog
Hugging Face - Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
量子位
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cybersecurity and Infrastructure Security Agency CISA
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog
V
V2EX
T
Tor Project blog
W
WeLiveSecurity
S
Security Archives - TechRepublic
I
Intezer
N
News and Events Feed by Topic
Y
Y Combinator Blog
Project Zero
Project Zero
I
InfoQ
Recent Commits to openclaw:main
Recent Commits to openclaw:main

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Как я написал «Обратную змейку» на чистом Canvas
Роман · 2026-06-16 · via Все публикации подряд на Хабре

Простой

7 мин

273

Змейка

Змейка

Начнём с небольшой предыстории: пару недель назад я ждал друга в кафе. Как обычно, он опаздывал примерно минут на сорок. Ноутбук с собой, интернет есть, а игр нет — чисто рабочая машина, ничего лишнего, хотя нужно будет что-то скачать, чтобы играть на работе 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 ООО «МТ ФИНАНС»