Контроллер и схемы ввода: путь сигнала
Механизм
Контроллер — это путь сигнала от пальца к процессору. Разберём по звеньям: алфавит → провод → часы опроса → конвейер задержки → парсер жестов.
D-pad: 8 направлений из 4 кнопок
До крестовины был аркадный джойстик — громоздкий, хрупкий, в карман не лезет. Гумпэй Ёкои (Game & Watch, 1982, затем NES) свёл направление к кресту из 4 моментальных переключателей (U/D/L/R). Нажал между двумя лучами — замкнул сразу два → диагональ. Сколько состояний даёт 4 бита и сколько из них легальны:
Вертикаль ∈ {U, D, ничего}, горизонталь ∈ {L, R, ничего} → 3 × 3 = 9 состояний (нейтраль + 8 направлений). Противоположные пары (U+D, L+R) физически невозможны/игнорируются — поэтому не 16. Дёшево (4 копеечных свитча), прочно (нет рычага), плоско — ключ к хэндхелду. Философия Ёкои: «латеральное мышление с увядшей технологией» — взять дешёвое зрелое железо и применить нестандартно.
Провод: защёлка и последовательный сдвиг
Контроллер NES — это микросхема 4021, 8-битный сдвиговый регистр. CPU не тянет 8 проводов от 8 кнопок. Вместо этого: сигнал latch (защёлка) разом параллельно загружает состояние всех 8 кнопок в регистр; затем CPU тактирует 8 раз, и на каждом такте из одного провода $4016 выпадает один бит — последовательно. Порядок жёсткий: A, B, Select, Start, Up, Down, Left, Right. Итого на опрос:
Зачем последовательно, если параллельно «быстрее»? Потому что дорог не такт, а провод: 8 жил в кабеле и 8 контактов в разъёме стоят денег и места. Один датавывод + latch + clock = 3 сигнала на любое число кнопок. Это тот же приём, что SPI/I²C: сериализуй, чтобы сэкономить пины. (Кнопки на pull-up: ненажатая = 1 в 4021, инвертируется для CPU.)
Часы опроса и конвейер задержки
Консоль читает пад обычно раз в кадр, в vblank (через NMI). Значит вход квантуется в 1/60 с — между двумя опросами мир не знает о кнопке. Дальше нажатие идёт по конвейеру: опрос → логика кадра → симуляция → рендер → вывод на экран (scanout). Каждое звено — кадр. Полная задержка «палец → пиксель»:
Числовой пример. Палец нажал сразу после опроса кадра N → ждёт ~1 кадр до следующего опроса, +1 кадр на обработку, +1 кадр на scanout до появления на экране:
На ЭЛТ-телевизоре 80-х это и был весь лаг; современный беспроводной пад + буферизующий ТВ добавляют ещё кадры. Опрос раз в кадр vs прерывание по фронту — классический выбор «poll vs interrupt»: пад опрашивают (просто, синхронно с кадром), хотя теоретически могли бы дёргать прерывание на нажатии.
Парсер жестов: моушены и input buffer
Файтинги превратили 8-направленный пад в алфавит жестов. Спецприёмы — это паттерны направлений + кнопка:
- Хадокен — quarter-circle-forward:
↓ ↘ →+ удар. - Шорюкен («драгон-панч», Z-моушен):
→ ↓ ↘+ удар. - Тацумаки — quarter-circle-back:
↓ ↙ ←+ ногой.
Движок держит скользящее окно последних нажатий (input buffer, ~8–16 кадров) и сопоставляет с шаблонами жестов. Буфер заодно прощает тайминг: команда, поданная на пару кадров раньше, всё равно сработает. Код Konami (↑↑↓↓←→←→BA) — та же буферизованная последовательность, а комбо — цепочки в окнах кадров. Это распознавание последовательности на потоке: окно = контекст, матч = крошечная sequence-модель.
🕹 В какие игры поиграть — и что заметить
Путь сигнала от «2 кнопки + крест» к «жест как слово» и «6 кнопок + шифты». По каждому: что в звене ввода сделано и что заметить руками.
D-pad + 2 кнопки (A/B) + Start/Select. Весь «язык» — 8 направлений и две кнопки. Код Konami (↑↑↓↓←→←→BA) — буферизованная последовательность, считанная тем же сдвиговым регистром; в Contra даёт 30 жизней.
🎮 Сыграй: введи код Konami на стартовом экране Contra. Заметь: важен порядок и окно ввода — это распознавание последовательности из потока сдвигового регистра, а не «волшебная кнопка».
Кнопка A бинарна (нажата/нет), но высота прыжка зависит от длительности удержания: игра считает, сколько кадров держат A, и кормит этим физику. Из одного бита выжата непрерывная нюансировка — интерпретация ввода, а не новое железо.
🎮 Сыграй: в SMB тапни A коротко и зажми надолго — высота разная. Это «сколько кадров держали кнопку», прочитанное опросом каждый кадр; чистая интерпретация бинарного входа.
Пад/стик стал алфавитом: ↓↘→ + удар = Хадокен. Движок сопоставляет окно входов с шаблоном; ширина окна — ручка «лёгкость vs ложные срабатывания». Аркадный стик и пад дают разную точность ввода одних и тех же жестов.
🎮 Сыграй: покрути Хадокены Рю. Поймай, как иногда фаербол вылетает случайно при ходьбе-прыжке (паттерн совпал в окне), а иногда «не читается» резкий моушен. Это буфер распознавания во плоти.
NES дал 2 кнопки, SNES — 4 лицевых (A/B/X/Y) + 2 шифта (L/R). Больше кнопок = больше глаголов без моушенов: переключение предметов, отдельный «бег», прицел. Шифты позже раскрыли схемы для гонок и Mode-7-игр.
🎮 Сыграй: в любой SNES-игре посчитай, сколько разных действий навешано на 6 кнопок против 2 на NES. Заметь, как шифты дают «модификатор» (как Shift на клавиатуре) — это расширение алфавита, а не скорости.
Главный дивиденд крестовины: направление, достаточно плоское для кармана. Тот же 4-свитчевый крест + 2 кнопки, что на NES, но в хэндхелде — то самое «латеральное мышление с увядшей технологией» Ёкои.
🎮 Сыграй: возьми любой Game Boy-эмулятор и почувствуй, что схема ввода идентична NES. Крест выиграл не выразительностью, а форм-фактором — он влез туда, куда джойстик не мог.
Хардкор · инженерия: почему опрос, а не прерывание, и где прячется лишний лагможно пропустить
Ввод можно читать двумя способами, и выбор не случаен.
Poll vs interrupt
Опрос: раз в кадр прочитал состояние пада — просто, детерминированно, синхронно с симуляцией (вход привязан к тому же fixed-step, что физика, см. m01). Прерывание: дёргать обработчик на каждом нажатии — реагирует мгновенно, но асинхронно, плодит гонки с обновлением состояния и недетерминизм (плохо для реплеев/нетплея). Игры берут опрос именно ради детерминизма: ввод кадра N принадлежит кадру N. Цена — события короче кадра невидимы.
Где набегает лаг сверх минимума
- Опрос не в начале кадра: читаешь пад поздно — теряешь до кадра.
- Глубокий конвейер рендера: 2–3 кадра «в полёте» ради пропускной способности (как batching в инференсе: throughput ↑, latency ↑).
- Буфер дисплея/ТВ: постобработка, кадровый буфер овердрайва — ещё кадры.
- Беспроводной пад: радиостек добавляет переменную задержку.
Минимизация «палец→пиксель» = ранний опрос + неглубокий конвейер + честный дисплей. Это бюджет латентности, тот же, что у любого интерактивного сервиса.
Алиасинг частоты опроса
Опрос 60 Гц ставит потолок на самый быстрый различимый ввод: тап короче ~16.7 мс, начавшийся и кончившийся между опросами, невидим (Найквист для пальцев). TAS эксплуатируют это покадрово; человеку приходится удерживать ввод через границу опроса.
Хардкор · дизайн: input buffer как ручка «точность ↔ прощение»можно пропустить
Буфер ввода — это окно из последних кадров, по которому распознаётся жест/команда. Ширина окна — единственная, но мощная ручка.
Шире окно — легче ввод, больше ложных
Жест ↓↘→ матчится, если все три направления встретились в пределах кадров. Большой : даже грязный, медленный моушен срабатывает (новичкам легче), но растёт ложное срабатывание — фаербол при обычной ходьбе-прыжке. Маленький : чисто, но требует точности. Это та же кривая precision/recall, что у wake-word-детектора: порог чувствительности гонит компромисс «пропуски vs ложные».
Прощение тайминга
Тот же буфер прощает ранний ввод: команда прыжка за пару кадров до приземления ставится в очередь и срабатывает в первый легальный кадр. В платформерах это «jump buffering» (см. game feel) — но там это выход (ощущение отзывчивости), а здесь — вход (механика распознавания из потока). Одна и та же буферизация, разные стороны звена.
Связь с комбо
Комбо — цепочка приёмов, каждый в своём окне «отмены» (cancel window): попал → в течение N кадров можно «отменить» восстановление в следующий приём. Тайминг комбо = последовательность окон буфера; фрейм-дата (см. кристаллизацию жанров) задаёт, какие окна вообще существуют.
ML / AI (твой домен): бюджет «палец→пиксель» = бюджет латентности инференса; стриминг LLM меряют TTFT (time-to-first-token) — тот же «запрос→первый пиксель». Input buffer ⇄ action chunking в imitation learning и робополитиках (ACT, VLA: предсказываем буфер из нескольких действий и проигрываем за несколько шагов — буферизация выхода). Распознавание моушена в окне ⇄ классификация последовательности по скользящему окну (окно буфера = контекст; матч = маленькая seq-модель; ширина окна = precision/recall, как у wake-word). А раскладка действий на кнопки ⇄ дизайн action-space в RL: как параметризуешь действия — то и выучиваемо.
Системы / железо: сдвиговый регистр = SPI/I²C и сериализация ради экономии пинов; latch = sample-and-hold; poll vs interrupt = busy-poll против epoll/IRQ и event loop; квантование опроса = частота дискретизации и Найквист.
UX / фронтенд: бюджет ввода = воспринимаемая отзывчивость (input latency); debounce/throttle = тот же input buffer; раскладка действий = affordances и горячие клавиши-модификаторы (Shift = «шифт» геймпада).
Принцип: сериализуй, чтобы экономить каналы; опрашивай с фиксированной частотой и считай весь конвейер «вход→отклик»; держи окно-буфер, чтобы распознавать жесты и прощать тайминг.
$4016 — поймаешь latch + 8 тактов опроса пада раз в кадр (в NMI/vblank). Включи отображение задержки кадров. Сравни игру, опрашивающую пад рано в кадре, с опрашивающей поздно — разница в лаге видна. В файтинге-эмуляторе найди окно input buffer: введи моушен «грязно» и «чисто», смотри, когда матчится.dt. Детерминизм ввода = детерминизм цикла.Зачем читать пад последовательно (1 провод, 8 тактов), если параллельно «быстрее»?
Если ввод опрашивается раз в кадр, что будет с тапом короче 16.67 мс?
Как игра отличает намеренный Хадокен (↓↘→) от случайного прохода этих направлений при ходьбе?
Почему D-pad не сделали аналоговым сразу — разве аналог не строго лучше?
Конвейер задержки — несколько кадров; почему не «опросил-обработал-показал» в один кадр, убив лаг?
- NESdev Wiki — Standard controller, 4021, Controller reading: первоисточник по защёлке и серийному чтению.
- David Sheff, «Game Over» — Гумпэй Ёкои и «латеральное мышление с увядшей технологией» (происхождение D-pad).
- Сообщество FGC: «frame data» и «input buffer» — как читаются моушены и комбо.
- Модуль 2, «Console Wars», разделы Controllers / Fighting Game Balance (
02-console-wars-1985-1993.md).