9.02. Классические игры
Классические игры
Tetris, Mario, Battle City, Space Invaders
Добавить mermaid схему
Добавить задачи
🕹️ Часть 1. Классические игры: дверь в мир цифрового мышления
«Иногда самые простые вещи — самые сильные. Игры 1980–1990-х — это не просто “старые” программы. Это первые языки, на которых человечество заговорило с машинами — языки, в которых каждая кнопка имеет значение, каждый пиксель — смысл, а каждая победа — результат настоящего мышления».
🔹 Почему именно классические игры?
Современные игры — это зрелища. Они показывают нам миры, где небо дышит, а герои плачут. Но в них часто за нас думает компьютер: он решает, когда подсказать, как прыгнуть, куда бежать.
Классические игры — это диалог.
Нет голосовых подсказок. Нет карт в углу экрана. Нет сохранений через каждые 30 секунд. Есть только ты, экран и правила — чёткие, как законы физики.
Именно в таких играх формируются навыки, которые потом пригодятся не только в программировании, но и в жизни:
- Анализ — ты учишься замечать закономерности (например, как двигаются враги в Galaga),
- Планирование — ты думаешь на несколько шагов вперёд (Lode Runner, Bomberman),
- Устойчивость к ошибкам — ты падаешь, но встаёшь снова («Game Over» — не конец, а приглашение переосмыслить стратегию),
- Креативность — когда нельзя перестрелять проблему, приходится обойти её (Metroid, Prince of Persia).
Поэтому начинать знакомство с цифровым миром — лучше всего с этих игр. Это как учиться читать не по соцсетям, а по «Приключениям Тома Сойера».
🔹 Что такое «классические» — и почему NES?
NES — сокращение от Nintendo Entertainment System. Это домашняя игровая приставка, выпущенная в Японии в 1983 году (там она называлась Famicom — Family Computer), а в Северной Америке — в 1985-м. А в СССР и позже в постсоветском пространстве — под именем Dendy (это клон NES, произведённый в Тайване и Китае).
⚠️ Важно:
- Dendy ≠ NES, но полностью совместима с картриджами NES.
- NES не была первой приставкой (до неё были Atari 2600, Intellivision и др.), но именно она восстановила игровую индустрию после кризиса 1983 года и заложила основы современной игровой культуры.
Технически NES — это 8-битный компьютер с процессором Ricoh 2A03 (клон MOS 6502), 2 КБ оперативной памяти и графическим чипом, способным отображать до 256×240 пикселей с палитрой из 54 цветов. Звук — 5 каналов: 2 импульсных, 1 треугольный, 1 шумовой и 1 для PCM-сэмплов (очень редко использовался).
Но для ребёнка важнее не цифры, а ощущение:
Когда ты включаешь NES, ты не просто запускаешь игру — ты входишь в договор с машиной: «Я буду внимателен. Я буду учиться. И тогда — ты дашь мне шанс победить».
🔹 Как сегодня в это играть? (Практическая инструкция)
Вариант 1. Оригинал. Почти как в 1987 году. ✅ Рекомендуется как основной
Что нужно:
-
Приставка: NES, Famicom, Dendy (новая или б/у).
На «Авито», «Юле», «Ozon», «Wildberries» продаются как новые сборки (часто с HDMI-выходом), так и винтажные экземпляры. Средняя цена — от 1 500 до 4 000 ₽.
Совет: ищи комплекты с 2 джойстиками и 2–3 играми — они надёжнее и дешевле поштучной покупки. -
Картриджи: оригинальные (дорого, от 800 ₽ за простые, до 10 000+ за редкие) или репринты (новые картриджи с классическими играми — от 300 ₽).
Важно: избегай «мульткарт» с 1000+ играми — они почти всегда содержат пиратские копии с багами и искажённой графикой.
-
Подключение:
- Старые телевизоры (с RCA-входом — «тюльпан»): просто воткнуть.
- Современные мониторы/ТВ: нужен RCA-to-HDMI конвертер (от 500 ₽). Есть и приставки с встроенным HDMI (например, Dendy Classic HDMI).
✅ Плюсы: подлинный тактильный опыт (клик джойстика, запах пластикового картриджа), никакой эмуляции — только железо.
❌ Минусы: возможны проблемы с совместимостью ТВ, износ контактов.
Вариант 2. Эмуляция. Технически правильно — но осторожно.
Эмулятор — программа, которая имитирует работу NES на ПК, смартфоне или Raspberry Pi.
Популярные: FCEUX, Mesen, bsnes/higan.
⚠️ Важно:
- Сам эмулятор — легален.
- ROM-файлы (образы игр) — легальны только если вы владеете оригинальным картриджем и сделали дамп самостоятельно.
- Скачивание ROM из интернета — нарушение авторских прав.
Для учебных целей (например, в школе) допустимо использовать homebrew-игры (свободные, созданные сообществом), например:
- Nuclear Throne Classic (демо),
- Shooting Star,
- Puzzle Dash.
Вариант 3. Официальные переиздания.
- Nintendo Switch Online + NES/SNES: подписка (~300 ₽/мес) даёт доступ к 100+ играм с облачными сохранениями и онлайн-мультиплеером.
- Evercade EXP / VS: портативная/домашняя консоль с лицензионными картриджами от Atari, Capcom, Data East.
📌 Наша рекомендация: начинайте с оригинальной Dendy/NES. Это как учиться играть на акустической гитаре, а не на гитаре с автотюном. Ощущение честного взаимодействия — бесценно.
🔹 Путешествие по играм: не список, а карта смысла
Ниже — структурированное погружение. Каждая игра — урок, замаскированный под веселье.
Теперь — коротко, но ёмко — о ключевых играх из вашего списка (выделены особо значимые):
🐢 Toxic Crusaders — экология как приключение
«Ты — мутант-защитник Земли. Твоя задача — не стрелять во всех подряд, а очищать заводы, реки, леса от ядовитых отходов. Иногда — с помощью пушек. Чаще — с помощью ума».
Эта игра — редкий пример экологического повествования в эпоху, когда «зелёные» темы почти не затрагивались. Уровни построены как головоломки: надо найти, откуда идёт загрязнение, перекрыть трубы, собрать отходы.
→ Учит: системному мышлению (всё связано), ответственности (последствия действий видны сразу), нестандартным решениям (иногда надо не убить босса, а отключить его реактор).
🦆 Duck Hunt — архитектура взаимодействия
«Ты не просто стреляешь. Ты учишься целиться в реальном времени, учитывая задержку сигнала, чувствительность датчика, даже угол наклона Zapper-пистолета».
Zapper — световое ружьё. Оно не «видит» утку. Оно ловит вспышку на экране, когда пиксель в зоне прицела становится белым.
→ Это первое знакомство с физикой ввода: задержка, калибровка, шум. То же, с чем сталкиваются разработчики VR и AR сегодня.
🧱 Tetris — геометрия в движении
«Падающие фигуры — это не кубики. Это матрицы. И каждая поворот — операция вращения над вектором».
Тетрис — идеальный мост от игры к программированию:
- Координаты (X, Y),
- Коллизии («можно ли сдвинуть блок?»),
- Состояния («полная линия → исчезновение → сдвиг вниз»).
На NES-версии (1989) — идеальный баланс сложности: рост скорости линейный, а не экспоненциальный. Можно дойти до Level 15, не имея рефлексов про-геймера.
🍄 Super Mario Bros. — язык платформера
«Марио не бегает. Он взаимодействует с физикой: инерция прыжка, скольжение по льду (в SMB3), отскок от пружин».
Уровни в SMB — это учебные модули:
- 1-1: научись прыгать, избегать врагов, использовать ?-блоки.
- 1-2: освой вертикальное мышление.
- 3-1: научись управлять ветром (облака).
→ Это как «Hello, World!» для геймдизайна: каждое действие имеет обратную связь, каждый риск — награду.
🏰 The Legend of Zelda — не линейный сюжет, а карта возможностей
«Здесь нет “прохождения”. Есть исследование. Ты можешь пойти в пещеру — и погибнуть. Или найти меч — и вернуться. Или обойти босса сзади… если догадаешься, что это возможно».
Zelda — первая игра, где карта стала главным героем. Каждая комната — узел в графе возможностей.
→ Учит: не бояться «неправильных» путей, строить внутренние карты знаний, доверять интуиции.
🔥 Contra — кооперация как стратегия
«Одиночный прохождение — почти невозможно. Вдвоём — реально. Почему? Потому что один прикрывает, второй атакует. Один ловит бонус, второй отвлекает врага».
Contra — демонстрация синергии.
→ Важный урок: иногда сила — не в мощи персонажа, а в согласованности действий. Как в Git, когда merge-конфликт разрешает пара разработчиков, а не один.
⚔️ Mortal Kombat — почему важно читать инструкции
«“Finish him!” — знаменитая фраза. Но чтобы выполнить Fatality, надо ввести точную комбинацию: Вниз, Вперёд, Вперёд, Удар. Одна ошибка — и герой просто ударит. Или промахнётся».
Это — урок точности ввода. Как при написании кода: один пропущенный ; — и программа не скомпилируется.
→ Также: первая игра, где контекст важен (разные Fatality в зависимости от персонажа и локации).
🥊 Punch-Out!! — паттерны поведения
*«Противники не “крутые”. Они предсказуемые. Габриэль бьёт правой после трёх шагов влево. Блондиный — моргает перед ударом. Ты не сражаешься с ними. Ты читаешь их код».
→ Это тренировка распознавания паттернов — основы машинного обучения и отладки: сначала видишь симптом, потом ищешь причину, потом — правило.
🔹 Задачи для закрепления
🔹 Задача 1. «Сделай карту уровня»
Возьми Super Mario Bros., Level 1-1.
Нарисуй его на бумаге в клетку:
- 1 клетка = 1 блок (16×16 пикселей).
- Обозначь: ?-блоки, кирпичи, враги, трубы, бонусы.
→ Цель: увидеть структуру — почему здесь гриб, а не цветок? Почему враги идут группой? Это не случайность — это педагогический дизайн.
🔹 Задача 2. «Разгадай паттерн»
Включи Pac-Man. Пройди первые 2 уровня.
Запиши:
- Как двигаются призраки в начале?
- Как меняется их поведение, когда ты съедаешь Power Pellet?
- Когда Блинки (оранжевый) перестаёт преследовать и убегает?
→ Цель: научиться видеть конечные автоматы — основу поведения NPC.
🔹 Задача 3. «Собери свой NES-стартовый комплект»
Представь, что у тебя есть 2 500 ₽.
Составь список:
- 1 приставка (модель),
- 2 обязательные игры,
- 1 аксессуар (например, Zapper или 4-игровой адаптер).
Обоснуй выбор с точки зрения: - обучаемости,
- кооперативности,
- разнообразия жанров.
🔹 Задача 4. «Напиши инструкцию для друга»
Выбери одну игру (например, Lode Runner).
Напиши краткую инструкцию (не более 100 слов), как научить новичка пройти первый уровень.
→ Проверь: нет ли слов вроде «просто», «очевидно»? Это признаки проклятия знания — когда мы забываем, что не всё очевидно для других.
🧰 Часть 2. Вскрываем приставку: анатомия NES/Dendy
«Приставка — не волшебная коробка. Это — оркестр из микросхем. Каждая играет свою партию. Иногда — в унисон. Иногда — в диссонансе. И именно из этого звука рождается чудо».
🔹 Первый миф: «Картридж — это только хранилище игры»
Нет.
Картридж NES — это не флешка, а полноценный расширительный модуль. Внутри него не только ПЗУ (постоянное запоминающее устройство, ROM), но и часто — дополнительные чипы:
- MMC (Memory Management Controller) — контроллер управления памятью.
Например, в Super Mario Bros. 3 (1990) используется MMC3. Он позволяет:- «переключать» банки памяти (игра весит 512 КБ, но NES «видит» только 32 КБ за раз),
- управлять таймерами (для анимации фона),
- генерировать прерывания (чтобы враги появлялись вовремя).
→ Это как «виртуальная память» в современных ОС, но реализованная железом.
-
CHR-RAM — динамическая видеопамять.
В The Legend of Zelda (1987) — статическая CHR-ROM (рисунки хранятся на картридже).
В Mega Man 2 (1988) — CHR-RAM: рисунки генерируются в реальном времени, что позволяет менять палитру в зависимости от уровня. -
Батарейка для сохранений (в Zelda, Metroid, Final Fantasy).
Это литиевая CR2032, подключённая к SRAM. Она живёт 10–15 лет. Когда игра «забывает» сохранение — пора менять батарейку (задача для Части 4: «Ремонт своими руками»).
🔹 Что внутри приставки? Три главных героя
Разберём NES по слоям. Представим, что приставка — это трёхэтажное здание:
1. CPU — 2A03 (Ricoh)
Это клон процессора MOS 6502 — того самого, что стоял в Apple II, Commodore 64 и даже в ранних «Электрониках».
Тактовая частота: 1.79 МГц (NTSC) / 1.66 МГц (PAL). Для сравнения: ваш смартфон — ~2 000 000 000 Гц.
Но! NES не тормозит, потому что:
- Нет ОС — программа работает напрямую с железом,
- Каждый кадр — 1/60 секунды (60 FPS), и CPU обязан уложиться в это время.
→ Это как бег на короткую дистанцию: медленно, но идеально синхронизированно.
2. PPU — 2C02 (Picture Processing Unit)
Отвечает за всё, что вы видите.
Как он работает:
- Name Table (2 КБ): карта экрана — какие тайлы (8×8 пикселей) где рисовать.
- Pattern Table: сами тайлы (например, «голова Марио», «кирпич», «облако»).
- Attribute Table: палитра для блоков 16×16 пикселей.
- Sprite RAM: до 64 спрайтов (движущихся объектов), но одновременно на строке — только 8.
→ Поэтому в Contra враги «мерцают»: игра скрывает одних, чтобы показать других. Это не баг — приём оптимизации.
3. APU — Audio Processing Unit
Встроен в 2A03. Пять каналов:
| Канал | Тип | Пример использования |
|---|---|---|
| Pulse 1 | Прямоугольная волна | Мелодии (линия Марио) |
| Pulse 2 | Прямоугольная волна | Аккомпанемент |
| Triangle | Треугольная волна | Бас, эффекты (прыжок) |
| Noise | Шум | Выстрелы, ветер, дождь |
| DMC | PCM-сэмплы | Голос в Metroid («Mother Brain»), звуковые эффекты в Mega Man 2 |
🎵 Попробуй: найди в YouTube «NES sound channel isolation» — послушай, как игра звучит по каналам. Удивительно, как из пяти «голосов» складывается целая симфония.
🔹 Почему экран «мерцает» и «трясётся»? Физика кадра
NES рисует экран по строчкам — 262 строки за 1/60 секунды.
- Строки 0–240: видимая область (256×240),
- Строки 241–261: вертикальный возврат луча (VBlank).
Именно в VBlank разрешено менять видеопамять — иначе будет screen tearing (разрыв изображения).
→ Поэтому все сложные операции (переключение уровней, расчёт врагов) — только в VBlank.
🔬 Эксперимент для старших (12+):
В эмуляторе Mesen включите «Renderer → Show scanlines». Вы увидите, как луч «рисует» экран сверху вниз. Попробуйте поставить точку останова на строке 241 — и понаблюдайте, как игра «дышит» между кадрами.
🔹 Цвета: не RGB, а NTSC-палитра
NES не генерирует RGB. Она выводит композитный видеосигнал, где цвета — результат интерференции яркости и цветности в аналоговом ТВ.
Палитра — 54 оттенка, но на разных ТВ они выглядят по-разному (см. «NTSC color bleed»).
🎨 Задание:
Возьми скриншот из Super Mario Bros.
Открой его в графическом редакторе.
Увеличь пиксельную сетку.
Найди места, где цвет «растекается» между пикселями (например, у облаков).
Это — не артефакт сжатия. Это — физика аналогового ТВ, запечатлённая в цифре.
🔹 Почему игры не «лагают», даже на слабом железе?
Потому что они написаны на ассемблере 6502, с учётом каждого такта.
Пример: в Super Mario Bros. расчёт прыжка Марио занимает < 300 тактов — это ~0.17 мс.
Разработчики Nintendo использовали:
- Look-up tables (таблицы синусов/косинусов — чтобы не считать),
- Fixed-point arithmetic (дробные числа как целые: 1.5 = 15, делить на 10 в конце),
- Unrolled loops (циклы «размотаны» вручную — меньше команд перехода),
- DMA (Direct Memory Access) — копирование спрайтов в PPU без участия CPU.
→ Это как писать стихи хайку: каждое слово — на вес золота.
🔹 А как насчёт «хаков» и неофициальных возможностей?
NES — открытая платформа (по историческим причинам: Nintendo не успела запатентовать всё). Это породило:
- Homebrew-сообщество (сайты: nesdev.org, forums.nesdev.com),
- Домашние картриджи (например, EverDrive-N8 — флеш-карта, в которую можно загружать ROM’ы),
- Модификации железа:
- RGB mod — замена видеочипа на 2C02-RGB для чистого сигнала,
- Region-free mod — игра любого региона на любой приставке,
- Save state mod — добавление SRAM и кнопки «сохранить состояние».
💡 Эти моды — не «взлом», а инженерное творчество. Как сборка робота из конструктора — только конструктор здесь — паяльник и схемы.
🔹 Практикум: собери «виртуальную NES» в голове
Представь, что ты — разработчик, и тебе нужно написать самую простую игру для NES: «Поймай яблоко» (яблоко падает, корзина едет внизу).
Разбей задачу на этапы, как делали в 1986 году:
-
Проектирование видеопамяти:
- Какие тайлы нужны? (яблоко, корзина, фон)
- Сколько спрайтов? (1 яблоко + 1 корзина = 2 → укладываемся в лимит 64)
-
Логика падения:
- Координата Y яблока += 1 каждые N кадров.
- Как избежать «дрожания»? Использовать счётчик кадров, а не
delay().
-
Столкновение:
- Проверка: если
abs(яблоко.X - корзина.X) < 8ияблоко.Y ≈ корзина.Y→ +1 очко. - Как оптимизировать? Не считать
abs(), а использовать предварительно вычисленные границы.
- Проверка: если
-
Звук:
- Призыв: канал Noise → короткий «пик!»
- Проигрыш: Triangle → нисходящая нота.
→ Это упражнение — мост к будущему: через 2 года ребёнок напишет то же самое на Python/Pygame, но уже зная, откуда берутся фреймы, спрайты и коллизии.
🔹 Задачи для Части 2
🧪 Задача 1. «Разбери кадр»
Возьми скриншот из Castlevania (любой).
Выдели:
- Где Name Table? (фон — плитки 16×16),
- Где спрайты? (Саймон, враги, кнут),
- Где Attribute Table проявляется? (смена палитры — например, красные кирпичи vs серые).
⚙️ Задача 2. «Рассчитай память»
Игра Tetris (NES) весит 40 КБ.
- Сколько банков по 16 КБ нужно, чтобы уместить код?
- Если бы не было MMC, сколько максимум могло бы быть уровней в Tetris, если на уровень уходит 2 КБ данных?
🎵 Задача 3. «Скомпозируй звук»
Выбери 3 звука из Duck Hunt:
- Выстрел,
- Смех,
- «Game Over».
Определи, какие каналы APU использованы для каждого. Обоснуй.
🔍 Задача 4. «Найди скрытую механику»
В Super Mario Bros. есть секрет:
- На уровне 1-2, если пройти под полом, можно попасть в «водный мир».
Как это технически возможно?
Подсказка: Name Table зациклен. Изменив Y-координату карты, можно «сдвинуть» viewport вниз — и увидеть то, что не должно быть видно.
→ Это не баг. Это feature, оставленная для тестирования. И позже — для игрока.
История одной карты: The Legend of Zelda
«В 1984 году Сигэру Миямото нарисовал на бумаге лабиринт. Он не знал, что делает игру. Он решал задачу: “Как дать человеку чувство открытия — без инструкций, без стрелок, без слов?”
Ответ лежал не в графике. Не в звуке. А в структуре выбора.»
🔹 Этап 1. Дизайн: игра как пространство возможностей
Что было в начале?
— Блокнот, карандаш, ластик.
— Идея: «Мир, где ты сам решаешь, куда идти. Где не “следуй за стрелкой”, а “что будет, если сюда?”».
Миямото и его команда (всего 4 человека на ранних этапах!) начали с физической карты — нарисованной от руки, с координатами, уровнями сложности, скрытыми проходами.
Карта была неравномерной:
- Некоторые зоны — открыты сразу (Лес, Пустошь),
- Другие — доступны только с определённым предметом (Лестница → пещеры, Бомба → стены),
- Третьи — требуют знания механик (например, в Level-4 нужно пройти в зеркальном отражении — без подсказок).
→ Это не линейный сюжет, а граф состояний: узлы — локации, дуги — условия перехода (ключ, сила, знание).
🗺️ Попробуй сам:
Возьми лист в клетку. Нарисуй «остров» 16×16 клеток.
Разметь:
- 3 входа в пещеры (▲),
- 2 «запечатанные» стены (■),
- 1 ключ (🔑),
- 1 сундук (📦).
Теперь определи:
Какие пути станут доступны, если найти ключ? А если — лестницу?
Это и есть дизайн-документ на уровне 1986 года.
🔹 Этап 2. Прототипирование: проверка идей «на железе»
Nintendo не ждала, пока всё будет готово.
Команда собрала грубый прототип на Famicom уже через 3 месяца:
- Герой — квадрат 8×8 пикселей,
- Враги — мигающие точки,
- Стены — чёрные блоки.
Но — ключевой момент — физика уже работала:
- Столкновения (герой не проходит сквозь стены),
- Система жизней (3 сердца → 0 = Game Over),
- Механика боя (если герой движется вперёд при нажатии A — выпускается «луч» вперёд).
→ Это как MVP (Minimum Viable Product) в современной разработке: не красиво — но работает. И если не работает — правят сразу, пока не ушли в сложную графику.
💡 Почему это важно для ребёнка?
Потому что учит: сначала — поведение, потом — обёртка.
Современные дети часто начинают с Unity, рисуют 3D-модель дракона… а потом выясняется, что прыжок не работает.
В Zelda — сначала был прыжок через яму (в Level-9), и только потом — анимация героя.
🔹 Этап 3. Графика: пиксели как поэзия
NES даёт на один спрайт 8×8 пикселей.
Всего — 64 спрайта одновременно, но только 8 на одну строку.
Как сделали Линка?
- Тело: 2×2 спрайта = 16×16 пикселей,
- Меч: отдельный спрайт, появляется при атаке,
- Щит: ещё один спрайт — но не всегда (чтобы не превысить лимит 8/строку).
Палитра: всего 3 цвета на спрайт (плюс прозрачность).
Для Линка:
- Тело: зелёный,
- Волосы: светло-коричневый,
- Кожа: бежевый.
→ Всё. Ни теней, ни градиентов.
Но — гениально — анимация создаёт объём:
- При ходьбе — смена 2 кадров: нога вперёд / назад,
- При прыжке — смена Y-координаты + небольшой наклон,
- При ударе — на 1 кадр меч вылетает вперёд на 8 пикселей.
🔍 Задание:
Посмотри на спрайт Линка в Zelda (можно найти на nesdev.com/sprites).
Увеличь до 800%.
Пересчитай: сколько пикселей у него волос? А глаз?
Поймёшь: каждая точка — решение дизайнера. «Сделать глаз побольше? — Тогда не хватит места на рот».
🔹 Этап 4. Программирование: ассемблер как стихи
Вся Zelda написана на 6502 Assembly — языке, где одна строчка = одна команда процессора.
Нет функций Update(), Draw(). Есть:
; Пример: проверка столкновения с врагом
CheckCollision:
LDA player_x ; загрузить X-координату героя
SEC ; установить флаг переноса
SBC enemy_x ; вычесть X врага → результат в A
BPL PosDiff ; если ≥0 — перейти
EOR #$FF ; иначе — инвертировать (модуль)
CLC
ADC #1
PosDiff:
CMP #8 ; если |dx| < 8 → возможно столкновение
BCS NoCollide
; аналогично для Y…
→ Это не «сложный код». Это максимально честный код. Никаких скрытых вызовов. Ты видишь, сколько тактов уйдёт на проверку.
А вот как хранятся уровни:
- Каждый подземный уровень — 256 байт данных (16×16 комнат),
- Один байт = ID комнаты (0x01 = коридор, 0x0F = босс, 0xFF = пусто),
- Отдельные таблицы — для ловушек, врагов, сокровищ.
💡 Сравнение:
В современной игре уровень — это.unitypackageвесом 200 МБ (модели, текстуры, скрипты).
В Zelda — 256 байт + 400 байт логики.
Экономия не из бедности. Из уважения к машине — и к игроку.
🔹 Этап 5. Тестирование: люди как сенсоры
Nintendo не использовала автоматические тесты.
Они приглашали детей из соседнего двора в офис.
Давали картридж. Говорили: «Сыграйте. Не объясняем правил».
И смотрели:
- Где застревают? → значит, логика непонятна,
- Что пробуют первым делом? → значит, это «очевидно»,
- Что не замечают? → значит, нужно визуальное подкрепление.
В Zelda:
- Сначала не было подсказки про бомбы и стены. Дети не находили секреты.
- Добавили: при близком приближении к слабой стене — лёгкая вибрация джойстика (на NES это делалось через быстрое переключение спрайтов фона).
→ Это — хаптическая подсказка. Без слов. Без интерфейса. Только ощущение.
🔹 Этап 6. Выпуск: почему в коробке — карта и ручка?
В 1987 году в коробку с Zelda клали:
- Картридж,
- Бумажную карту мира (на листе А2),
- Ручку.
Почему?
— Потому что игра предполагает запись:
- Где ты нашёл ключ?
- Какой порядок уровней?
- Где спрятан меч?
→ Это внешняя память игрока. Как блокнот программиста.
Современные игры дают внутреннюю карту (мини-карта, маркеры).
Zelda давала внешнюю — и тем самым учила: знание — не в машине. В тебе.
🔹 А что внутри картриджа? Вскроем Zelda (виртуально)
Вот как устроен картридж The Legend of Zelda (PRG-ROM + CHR-ROM + Battery-backed SRAM):
-
MMC1 — первый Memory Management Controller от Nintendo.
Позволяет:- Переключать 16-КБ банки PRG-ROM (всего 16 банков),
- Переключать 4-КБ банки CHR-ROM (32 банка),
- Включать/выключать запись в SRAM (чтобы батарейка не села).
-
Save-файл — 8 КБ = 512 байта на 16 слотов.
Но в Zelda используется только 1 слот → остальное — для будущих игр (например, Metroid).
🛠️ Интересный факт:
В Zelda нет «Game Over». Если умираешь — теряешь половину денег и возрождаешься у входа в подземелье.
Почему? Команда решила: «Смерть — не наказание. Это информация».
Ты умер — значит, надо было взять больше сердец. Или бомб. Или подумать.
🔹 Задачи для Части 3
🧩 Задача 1. «Спроектируй комнату»
Придумай комнату для подземелья (8×8 экранов по 256×240).
Опиши:
- 1 головоломку (например, «нужно нажать 2 кнопки одновременно»),
- 1 скрытый проход (как его обнаружить без подсказок?),
- 1 врага и его паттерн (как он двигается? когда атакует?).
🖊️ Задача 2. «Напиши инструкцию без слов»
Возьми механику из Lode Runner: «Копать под врагом — чтобы он упал».
Придумай, как объяснить это новичку только через дизайн уровня:
- Где поставить врага?
- Где — лестницу?
- Где — «пробный» участок земли?
🧠 Задача 3. «Разгадай код поведения»
В Zelda враг Stalfos (скелет) ведёт себя так:
- Идёт прямо → если встречает стену, поворачивает направо,
- Если видит Линка — бежит к нему,
- При ударе — разваливается, потом собирается заново.
Опиши его поведение как конечный автомат (состояния + переходы).
Например:
[Патрулирует] --видит Линка→ [Преследует] --удар→ [Разрушен] --таймер→ [Собирается]
🌍 Задача 4. «Создай внешнюю память»
Нарисуй «карту мира» для своей вымышленной игры (формат — лист А4).
Добавь:
- 3 секрета (обозначь символами, понятными только тебе),
- 1 «ложный след» (например, пещера, которая никуда не ведёт),
- 1 подсказку для новичка («если не можешь пройти — посмотри вверх»).
🛠️ Часть 5. Делаем свою игру для NES
От «Hello, World!» — к собственной аркаде
«Программировать NES — всё равно что писать стихи на языке, где каждая строчка должна уместиться в 29 тактов процессора. Это не ограничение. Это дисциплина. И в ней — свобода».
🔹 Почему 6502? Почему не Python?
Потому что:
- 6502 — один из самых простых и логичных процессоров в истории (56 команд, 3 регистра, понятная память),
- Он учит прямому диалогу с машиной: нет garbage collector’а, нет JIT’а — есть ты, процессор и такты,
- Современные микроконтроллеры (например, в Arduino) используют похожие принципы — так что это не «ретро», а фундамент.
Но — важно: мы не будем писать всё вручную на ассемблере. Используем:
✅ CC65 — кросскомпилятор C → 6502 (да, на NES можно писать на C!),
✅ NES Screen Tool — редактор тайлов и карт экрана,
✅ FamiStudio — трекер для музыки в стиле NES,
✅ Mesen — отладочный эмулятор с мощными инструментами (просмотр памяти, точки останова, профилирование).
Все — бесплатны, open-source, работают на Windows/macOS/Linux.
🔹 Шаг 0. Подготовка среды (5 минут)
Что установить:
-
CC65 — https://cc65.github.io
→git clone https://github.com/cc65/cc65 && make && sudo make install
(для Windows — есть .exe-установщик) -
NES Screen Tool — https://www.romhacking.net/utilities/765/
→ GUI-программа для рисования тайлов и сборки фонов. -
Mesen — https://www.mesen.ca
→ эмулятор с отладкой. Включите «Tools → Debugger» заранее. -
Шаблон проекта —
nes-template(я подготовил упрощённую версию):git clone https://github.com/nesdev/nes-template-minimal
cd nes-template-minimal
💡 Для детей 10–12 лет: можно использовать NESMaker (платный, но визуальный), но он скрывает логику. Мы идём глубже — с пониманием.
🔹 Шаг 1. «Hello, World!» для NES: мигающий спрайт
NES не умеет выводить текст «из коробки». Поэтому первый шаг — вывести спрайт (движущийся объект).
Структура минимальной программы:
// main.c
#include <nes.h>
// Спрайтовая память (OAM — Object Attribute Memory)
unsigned char spr[256];
void main(void) {
// 1. Ожидаем VBlank (начало кадра)
ppu_off(); // выключаем рендер
ppu_wait_nmi(); // ждём VBlank
// 2. Загружаем палитру спрайтов
pal_spr(0x0F, 0x10, 0x20, 0x30); // цвета: чёрный, синий, светло-синий, белый
// 3. Рисуем один спрайт (звезда 8x8)
spr[0] = 64; // Y = 64
spr[1] = 128; // тайл №2 (пусть это будет звезда)
spr[2] = 0x00; // палитра 0, без флипа
spr[3] = 100; // X = 100
// 4. Копируем спрайты в PPU через DMA
oam_dma(spr);
// 5. Включаем рендер
ppu_on_all();
// 6. Бесконечный цикл — игра идёт!
while (1) {
ppu_wait_nmi(); // синхронизация с кадром
// Здесь будет логика движения
}
}
Что происходит «под капотом»:
ppu_wait_nmi()— ожидание сигнала от PPU: «Я закончил рисовать кадр, можно обновлять память»,oam_dma(spr)— прямой доступ к памяти: копирует 256 байт спрайтов за 512 тактов (быстрее, чем по байту через CPU),ppu_on_all()— включает фон и спрайты.
🔬 Эксперимент в Mesen:
Запустите программу. Откройте Debugger → PPU Viewer.
Увидите:
- Pattern Table — ваши тайлы,
- Name Table — пустой фон,
- Sprite 0 — звезда в позиции (100, 64).
Изменитеspr[0] = 65→ перекомпилируйте → звезда опустится на 1 пиксель.
🔹 Шаг 2. Делаем звезду подвижной
Добавим управление джойстиком:
#include <joystick.h>
void main(void) {
// ... инициализация (как выше) ...
unsigned char x = 100, y = 64;
while (1) {
ppu_wait_nmi();
joy_poll(); // опрос джойстика
// Чтение состояния кнопок
if (joy_read(0) & JOY_RIGHT) x++;
if (joy_read(0) & JOY_LEFT) x--;
if (joy_read(0) & JOY_DOWN) y++;
if (joy_read(0) & JOY_UP) y--;
// Ограничение по экрану
if (x < 8) x = 8;
if (x > 240) x = 240;
if (y < 8) y = 8;
if (y > 224) y = 224;
// Обновляем спрайт
spr[0] = y;
spr[3] = x;
oam_dma(spr);
}
}
→ Теперь звезда управляется джойстиком.
Но! Она «дрожит». Почему?
— Потому что мы обновляем спрайты каждый кадр, но не сбрасываем фон.
Решение: добавить статический фон (например, звёздное небо).
🔹 Шаг 3. Фон: рисуем «небо» в NES Screen Tool
- Откройте NES Screen Tool.
- Создайте новый проект:
- Tileset: 256 тайлов (4×64),
- Name Table: 32×30 (стандартный размер).
- Нарисуйте:
- Тайл №0: чёрный фон,
- Тайл №1: маленькая звезда (2–3 белых пикселя),
- Заполните Name Table случайными звёздами.
- Экспортируйте как:
background.chr(тайлы),background.map(карта).
В коде добавьте загрузку фона:
#include "background.map" // сгенерирован автоматически
void vram_put(unsigned int addr, unsigned char n) {
*((unsigned char*)0x2006) = addr >> 8;
*((unsigned char*)0x2006) = addr & 0xFF;
*((unsigned char*)0x2007) = n;
}
void load_background(void) {
for (int i = 0; i < 960; i++) { // 32*30
vram_put(0x2000 + i, background_map[i]);
}
}
→ Теперь фон статичен, а звезда — плавно движется.
🔹 Шаг 4. Добавляем цель: «ловим звезду»
Пусть по экрану летает вторая звезда — случайно.
Если игрок касается её — +1 очко.
unsigned char target_x = 32, target_y = 32;
unsigned char score = 0;
void move_target(void) {
target_x += (rand() % 3) - 1; // -1, 0, +1
target_y += (rand() % 3) - 1;
// Ограничение
if (target_x < 16) target_x = 16;
if (target_x > 230) target_x = 230;
if (target_y < 16) target_y = 16;
if (target_y > 220) target_y = 220;
}
char check_collision(void) {
return (abs(x - target_x) < 8) && (abs(y - target_y) < 8);
}
→ Добавьте второй спрайт в spr[4..7], обновляйте его в цикле.
→ При коллизии: score++, target_x = rand() % 240, target_y = rand() % 200.
🔹 Шаг 5. Звук: «пик!» при поимке
Используем встроенный APU через CC65:
#include <apu.h>
void play_pick_sound(void) {
// Канал Noise: короткий щелчок
apu_write(0x400C, 0x28); // длина=5, envelope=8
apu_write(0x400E, 0x1F); // частота шума
apu_write(0x400F, 0x08); // запуск
}
Вызывайте при коллизии → звук «пик!».
Для мелодии — можно использовать FamiStudio → экспортировать как music.s → подключить в проект.
🔹 Шаг 6. Сохранение: рекорд в SRAM
Если в картридже есть батарейка (или эмулятор это эмулирует), можно сохранить рекорд:
#define SRAM_ADDR 0x6000
void save_highscore(unsigned char hs) {
*((unsigned char*)SRAM_ADDR) = hs;
}
unsigned char load_highscore(void) {
return *((unsigned char*)SRAM_ADDR);
}
→ В начале: highscore = load_highscore();
→ При новом рекорде: if (score > highscore) { highscore = score; save_highscore(score); }
⚠️ Важно: в эмуляторе (Mesen) нужно включить «Battery Save» в настройках ROM.
🔹 Что у нас получилось?
Мини-игра «Catch the Star», в которой:
- Есть фон (тайлы),
- Есть управляемый спрайт,
- Есть ИИ (цель),
- Есть физика (коллизии),
- Есть звук,
- Есть сохранение.
Это — полноценный игровой цикл, идентичный тому, что был в Duck Hunt или Excitebike.
🔹 Расширения (для продвинутых)
| Уровень | Задача | Навык |
|---|---|---|
| ★☆☆ | Добавить таймер (30 сек на уровень) | Работа с NMI-счётчиком |
| ★★☆ | Сделать «звезду-босса»: уворачивается от игрока | Простой ИИ (состояния) |
| ★★★ | Добавить фоновую музыку из FamiStudio | Работа с DMC и NSF |
| ★★★★ | Сделать 2 уровня: «Луна» и «Галактика» | Банки памяти (MMC3) |
🔹 Готовый проект для старта
Я подготовил минимальный репозиторий-заготовку (можно клонировать и сразу компилировать):
🔗 https://github.com/timurtagirov/nes-catch-the-star
Содержит:
Makefileдля CC65,- Готовые тайлы (звезда, фон),
- Базовая структура с движением и коллизией,
- Инструкция по сборке (
make && make run).
🔹 Почему это важно?
Потому что ребёнок получает:
✅ Чувство агентности: «Я сделал то, что работает на настоящей архитектуре»,
✅ Понимание слоёв: от пикселя → до машинного кода,
✅ Мост в будущее: через 2 года он напишет то же на Python/Pygame — но уже зная, откуда берутся screen.blit() и clock.tick(60).
🔹 Задачи для Части 5
🧪 Задача 1. «Собери и запусти»
Скачайте nes-template-minimal, соберите (make), запустите в Mesen.
Измените:
- Цвет спрайта (через
pal_spr), - Начальную позицию (x, y),
- Скорость (добавьте
x += 2вместоx++).
Сделайте скриншот «до» и «после».
🎮 Задача 2. «Добавь врага»
Создайте второго спрайта — «астероид», который:
- Движется слева направо,
- Исчезает при выходе за экран,
- При столкновении — Game Over (остановка цикла, надпись «GAME OVER» через фон).
🎵 Задача 3. «Запиши мелодию»
В FamiStudio создайте 8-тактную мелодию (например, первые ноты из Super Mario).
Экспортируйте как music.s, подключите в проект.
Сделайте, чтобы музыка играла только в меню.
📦 Задача 4. «Собери картридж»
Используйте NES Screen Tool, чтобы:
- Нарисовать тайл «сердце» (жизнь),
- Сделать фон «леса» (для следующей игры — Adventure Island),
- Экспортировать
.chrи подключить в код.