Skip to content

12 — Interview questionnaire ​

How to run this interview ​

The questions below are written in Russian. Conduct the interview in whatever language the user writes to you in — translate on the fly.

Rules:

  1. Read the SDK documentation first (order: README.md). Half the value of this interview is your ability to say "the engine already does that" instead of letting the user design a feature that cannot exist.
  2. One block at a time. Ask a block, get the answers, confirm your understanding in one sentence, move on. Never dump all 14 blocks at once.
  3. Every question has a "как в tanks" default. State it, and let the user accept it with a single word. Blocks 1, 5, 6, 7, 10 are the ones that really define the game — spend the time there.
  4. Push back immediately on impossible answers. The list of things that do not exist is at the end of pitfalls.md. Offer the nearest workable alternative in the same message.
  5. Skip what is already settled. If the user described the game in the first message, do not re-ask; confirm instead.
  6. After the last block, write the design document and get confirmation before generating anything.

Блок 1. Идентичность игры и пакет ​

  1. Как называется игра? Нужен короткий id (латиница, без пробелов) — он станет manifest.id, сегментом URL /games/<id>/ и должен совпасть с идентификатором, под которым игра зарегистрирована на платформе. В tanks — tanks.
  2. Имя npm-пакета? Конвенция — @vimp-games/<id>; собственный scope тоже допустим. В tanks — @vimp-games/tanks.
  3. Отображаемое название (manifest.title) — то, что видит игрок в лобби. В tanks — VIMP Tanks.
  4. Одним абзацем: что это за игра, какой жанр, чем игрок занимается в матче? (Нужно для выбора формы сущностей и снапшота.)

Блок 2. Комната и лобби ​

  1. Какой целевой размер комнаты (roomDefaults.maxPlayers)? Учтите: платформа в любом случае клампит до 8. В tanks — 8.
  2. Какие поля должны быть в форме создания сервера? Важно: хост принимает только maxPlayers, map, roundTime, mapTime, friendlyFire (плюс каталог карт). Любое собственное поле формы будет принято формой и молча отброшено — настройку, влияющую на правила, через форму комнаты передать нельзя. Если такая настройка нужна, обсудим, как зашить её в конфиг игры или в логику ядра.
  3. Доступные контролы формы — только text, select, checkbox, radio (в v3 движка нет range/number/toggle). Числовые границы задаются полями min/max и автогенерируемым regExp. Годится?
  4. Огонь по своим (friendlyFire) по умолчанию включён или выключен? В tanks — выключен (false), игрок может переключить при создании комнаты.
  5. Длительность раунда и карты по умолчанию? В tanks — 120 с и 600 с; пользовательские значения клампятся в 10 с … 3600 с.

Блок 3. Экран входа (auth) ​

  1. Что игрок выбирает перед входом в матч? (Модель/класс/цвет/фракция — любой набор полей.) Ника среди них нет: имя берётся из JWT лобби. В tanks — только модель танка.
  2. Тексты экрана: заголовок и блок подсказок (обычно раскладка управления — пары «клавиши → действие»). Дайте формулировки.
  3. Какие из полей должны запоминаться между сессиями (storage) и какие нужно проверять на стороне хоста (validator)? В tanks — модель запоминается и валидируется по списку моделей.

Блок 4. Правила матча, чат, голосования ​

  1. Раунд заканчивается уничтожением всей команды противника — это правило движка. Подходит? Если игра не раундовая, обсудим обходные варианты (одна длинная «партия», один играющий тим, респавн внутри ядра).
  2. Что происходит с игроком после смерти? В движке он становится наблюдателем за убийцей до конца раунда. Нужен ли респавн внутри раунда — это реализуется в вашем Rust-ядре, не конфигом.
  3. Нужно ли окно неуязвимости после респавна? В движке такого нет — реализуется в ядре (флаг на акторе + проверка в расчёте урона).
  4. Голосования: какие типы нужны, кроме встроенных teamChange и mapChange? Учтите кулдаун категории 30 с, окно голосования 10 с, одно активное голосование за раз, ничья разрешается случайно. Голосования за кик игрока в движке нет, эндпоинта /ban и рейтинга серверов (/like//unlike) тоже нет.
  5. Какие чат-команды нужны игре? Движок своих не разбирает — весь набор объявляет игра (HostPlugin.chatCommands). Обычный минимум: /rank, /nr (dev), плюс /timeleft и /mapname, если раунд и карта конечны. В tanks есть все четыре и своя /bot, в snakes — только /nr, /rank и /bot.
  6. Какие системные сообщения чата добавляет игра? Буквы групп s, v, m, c заняты движком — выберите свою (в tanks это b). Нужны тексты с плейсхолдерами {0}, {1}.
  7. Максимальная длина сообщения чата? По умолчанию 60 символов.
  8. Нужно ли менять политику киков? Дефолты: неактивность 120 с для игрока (для наблюдателя выключено), кик по средней задержке > 1000 мс, кик после 5 пропущенных пингов, пинг каждые 3 с, проверка неактивности каждые 30 с.

Блок 5. Управление и предикция ​

  1. Полный список действий игрока с назначенными клавишами. Для каждого: удержание (движение) или разовое срабатывание (выстрел, смена оружия)? Разовые действия потребляются один раз за тик, up игнорируется.
  2. Что делают клавиши наблюдателя? Обязательный минимум — nextPlayer и prevPlayer. В tanks — n/p.
  3. Нужна ли клиентская предикция движения (мгновенный отклик своего актора)? Без неё управление ощущается с задержкой ~100 мс + пинг. Ограничение: предсказываемое состояние — ровно 8 × f32. Перечислите, какие величины туда войдут. В tanks — x, y, угол корпуса, угол орудия, vx, vy, нагрузка двигателя, состояние.
  4. Нужна ли предикция выстрела (мгновенный визуальный эффект до прихода авторитетного события)? Если да — потребуется подавление дублей по id автора в событийном блоке.

Блок 6. Оружие и боевая механика ​

  1. Список оружия/способностей. Для каждого: тип поражения (мгновенный луч, снаряд с полётом, взрыв по радиусу, что-то иное), урон, дальность, разброс, импульс, тряска камеры.
  2. Перезарядка задаётся полем fireRate в секундах (0 — без кулдауна). Укажите значения.
  3. Боезапас: стартовые значения патронов задаются значениями полей панели (panel.fields[*].value) — то же число уходит в ядро как стартовый ресурс. Сколько и чего?
  4. Есть ли модели/классы актора с разными характеристиками? Для каждой: габариты, ускорение, максимальная скорость, поворот, демпфирование, плотность/трение/отскок, стартовое оружие.
  5. Нужны ли игровые события, которые движок не понимает (подбор предмета, захват точки, начисление очков вне убийств)? Такие события идут через custom → HostPlugin.onCoreEvent.

Блок 7. Снапшот и сущности ​

  1. Перечислите все сущности, которые видит клиент: игроки, снаряды, эффекты, динамические объекты карты.
  2. Для каждой сущности — какие поля передавать и с какой точностью (f32, u8, u16, u32)? Какие из них интерполировать (lerp), какие как угол (lerpAngle), какие дискретно?
  3. Для каждой сущности — форма блока:
    • indexed8 — до 255 адресуемых объектов (игроки);
    • indexed32 — много короткоживущих объектов с id (снаряды в полёте);
    • list16 — анонимные разовые события (трассеры, взрывы);
    • indexedNoNull8 — фиксированные слоты (динамика карты). Ограничение: в hot-буфер (плавный рендер каждый кадр) попадают только indexed8 и indexedNoNull8. Всё остальное приходит событиями.
  4. В каждом событийном блоке оружия последнее поле — id автора выстрела (нужно для подавления дублей предсказанного эффекта). Подтвердите.

Блок 8. HUD, статистика, звуки, информ-сообщения ​

  1. Какие ресурсы показывает панель? Для каждого: тип ячейки — bar (полоса, по умолчанию 30 блоков, максимум 100), value (число), weapon (подсвечивается активное), time (M:SS). Ячейка времени раунда обязательна и жёстко привязана к ключу t.
  2. Таблица статистики: движок пишет ровно пять величин — name, status, score, deaths, latency (это и есть «пинг»). Свои колонки движок заполнять не будет. Нужны заголовки колонок и порядок сортировки (численной). Агрегаты команды считаются методами '=' (замена), '+' (накопление), '#' (счёт строк).
  3. Звуки: полный список с приоритетами (важнее — выше; лимит 30 одновременных пространственных голосов) и громкостями. Каждый звук нужен парой webm + mp3.
  4. Маппинг движковых событий на ваши звуки: roundStart, victory, defeat, frag, death. Какие из них нужны?
  5. Тексты трёх информ-сообщений (индексы фиксированы): победа команды ({0} — команда), старт раунда, конец игры. В tanks — {0} WINS!, ROUND START!, GAME OVER!.
  6. Нужно ли голосование сразу после входа в матч (initialVote)? В tanks — выбор команды. Если игра одно-командная и наблюдателей в ней нет как явления — ответ «нет»: вместо initialVote/spectatorTeam объявляется gameConfig.noSpectators: true (ровно одна команда, вход прямо в неё), а modules.vote можно не объявлять вовсе. Если раунд в игре бесконечный — к нему же gameConfig.endlessRound: true.

Блок 9. Боты (scripted-участники) ​

  1. Нужны ли боты? Если да — как они должны себя вести (искать ближайшего противника, патрулировать, держать позицию)? Уточните желаемое поведение, а не числовые константы: частота решений ИИ и прочие параметры — это код Rust-ядра, а не настройка конфига.
  2. Как боты создаются: чат-командой, голосованием, автоматически при нехватке игроков? В tanks — команда /bot с голосованием.
  3. Префикс имени и модель бота по умолчанию?

Блок 10. Карты и окружение ​

  1. Сколько карт нужно в первой версии и какого размера (в тайлах)?
  2. Тайлы: какой размер тайла (step) и какие индексы делают стену (physicsStatic)? Картинки тайлов везёт ваш пакет — движок игровых картинок не раздаёт вовсе. Какие файлы тайл-листов вы кладёте в assets/img/ (оттуда они попадут в dist/img/ и приедут клиенту как ${assetsBase}img/<файл>)?
  3. Слои отрисовки: какие индексы тайлов на каком слое (layers)?
  4. Нужны ли динамические объекты (ящики, бочки)? Для каждого: позиция, размер, плотность, картинка, слой, демпфирование. Картинка — тоже файл из assets/img/ вашего пакета.
  5. Точки респавна: их количество на команду — жёсткая вместимость этой команды на карте. Сколько точек на команду? (Должно покрывать maxPlayers.)
  6. Масштаб карт (mapScale, и при необходимости scale у отдельной карты)? В tanks — 0.3, у отдельных карт свой.
  7. Сколько карт предлагать в голосовании за ротацию (mapsInVote)? В tanks — 4.

Блок 11. Канвасы, камера и клиентский UI ​

  1. Сколько полотен нужно? В tanks — основное (vimp) и радар (radar). Для каждого: стартовый размер, соотношение сторон (aspectRatio) или фиксированный размер (fixSize), базовый масштаб (baseScale).
  2. Нужна ли динамическая камера (смещение вперёд по скорости + отдаление) и тряска камеры на попаданиях/взрывах?
  3. Какие DOM-элементы показывать после авторизации (initIdList)? Обычно — все полотна плюс panel и chat.
  4. Есть ли собственные стили (цвета команд, оформление панели)? CSS игры отдаётся движку строкой. Учтите: движковый CSS рассчитан на пять колонок статистики и классы .line1–.line3.
  5. Будут ли частицы/эффекты в больших количествах (дым, искры)? Если да — планируем пул объектов, иначе сборщик мусора будет заметен.
  6. Каким частям нужны сервисы renderer и soundManager? (Пул сервисов фиксирован этими двумя.)

Блок 12. Сетевые допущения ​

  1. Какие сущности обязаны выглядеть плавно (интерполяция/предикция), а какие достаточно показывать по событию?
  2. Частота отправки кадров: по умолчанию каждый 4-й тик симуляции — 30 кадров/с при тике 120 Гц. Оставляем?
  3. Есть ли в игре подбираемые предметы, разрушаемые объекты или захватываемые точки? В движке их нет — моделируются ключами снапшота (обычно indexedNoNull8 или indexed8) плюс логикой ядра. Нужны?
  4. Что должно доезжать гарантированно (события, тряска), а что можно терять (позиции)? По умолчанию кадр уходит по надёжному каналу, если в нём есть события, forceReset или тряска.
  5. Должна ли игра переживать смену хоста посреди раунда (новый хост продолжает с того же тика)? Да — gameConfig.migration.midRound: true, и тогда всё состояние ядра обязано быть в GameSim::serialize, а у host-модулей с состоянием — serializeState/restoreState. Нет — при смене хоста раунд начинается заново (мягкий режим, по умолчанию).

Блок 13. Прогрессия ​

  1. Нужна ли прогрессия между матчами? Движок хранит rank (целое число, общий формат для всех игр) и state (произвольный JSON вашей игры).
  2. rank движок считает сам: +1 за фраг, −1 за тимкилл. Хука для изменения этого правила нет. Устраивает?
  3. Что положить в state и с чего начинать новому игроку (playerState.defaultState)? Данные пишутся из onCoreEvent и синхронизируются на конце раунда, смене карты и выходе игрока.

Блок 14. Процесс ​

  1. Нужен ли cargo-тест паритета движения (предиктор против авторитетной симуляции)? Настоятельно рекомендуется — без него расхождение предикции обнаруживается только глазами в игре.
  2. Нужен ли JS↔WASM интеграционный харнесс (тесты, гоняющие настоящее ядро через pkg-node)?
  3. Локализация: движок не поддерживает переключение языка в рантайме — все тексты (чат, панель, голосования, информы, экран входа) задаются одним набором в конфиге. На каком языке пишем тексты?
  4. Как запускаете игру локально во время разработки? npm run dev (standalone-вкладка с ботами) и npm run sim работают без чекаута движка. Нужен ли собственный dev-харнесс сверх шаблонного dev/main.js?
  5. Публикуем ли в манифесте entries.wasmNode (путь к core/pkg-node)? Настоятельно рекомендуется: без него игру нельзя прогнать headless-runner'ом движка (npm run sim), и все проверки контрактов придётся делать глазами в браузере. См. debugging.md.
  6. Какие сценарии отладочных прогонов пишем сразу (движение, стрельба, смерть/респаун, конец раунда, смена карты, голосование)? Сценарий — обычный JSON, формат в debugging.md.
  7. Реализуем ли GameClientDef::predicted_state (опционально, дефолт None) ради покомпонентного отчёта о расхождении предикта? Без него работает грубое сравнение по камере.

Answer → artifact map ​

BlockProduces
1package.json, scripts/build-game-manifest.js, id/title in both plugins
2gameConfig.roomDefaults, gameConfig.roomForm, parts.friendlyFire, timers.roundTime/mapTime
3src/config/auth.js (elems, texts, params, validators)
4gameConfig.teams/spectatorTeam (или noSpectators, и тогда без initialVote, spectatorTeam и modules.vote), endlessRound, chatMaxLength, idleKickTimeout/rtt, src/host/systemMessages.js, chat commands, client modules.chat.params.messages, modules.vote.params
5gameConfig.playerKeys, client modules.controls.keySetList, spectatorKeys, core apply_input, predictor.rs, PLAYER_STATE_LEN layout
6src/data/weapons.js, src/data/models.js, core weapon modules, onCoreEvent for custom events
7src/config/snapshot.js, Rust build_snapshot_blocks rows, client parts.gameSets
8gameConfig.panel + client modules.panel, gameConfig.stat + client modules.stat, src/config/sounds.js, gameConfig.soundCues, gameInform.list
9gameConfig.scripted, src/host/<Bot>Manager.js, createModules, bot chat command, core/src/bots/
10src/data/maps/*.js, gameConfig.maps/currentMap/mapScale/mapSetId/mapsInVote, map parts
11client modules.canvasManager.canvases, initIdList, styles, parts.bakedAssets, parts.componentDependencies
12snapshot kind/class decisions, timers.networkSendRate, extra snapshot keys for pickups/objectives, gameConfig.migration.midRound + GameSim::serialize coverage + module serializeState/restoreState, a checkpointRestore step in the sim scenario
13gameConfig.playerState.defaultState, onCoreEvent state writes
14vitest.config.js projects, core/src/client/predictor.rs parity tests, tests/, the dev/ harness, entries.wasmNode in the manifest, debug scenarios for npm run sim, optional predicted_state

vimp-engine 0.38.1 · vimp-engine-core 0.23.2 · create-vimp-game 0.5.4