Skip to content

Опросник для интервью ​

Как вести интервью ​

Ведите интервью на том языке, на котором пишет пользователь — переводите вопросы на лету.

Правила:

  1. Сначала прочитайте документацию SDK (порядок: README.md). Половина пользы от интервью — ваша способность сказать «это движок уже делает», а не дать пользователю проектировать функцию, которой не может быть.
  2. По одному блоку. Задайте блок, получите ответы, подтвердите понимание одной фразой, переходите дальше. Никогда не вываливайте все 14 блоков сразу.
  3. У каждого вопроса есть вариант «как в tanks». Назовите его и дайте пользователю принять одним словом. Блоки 1, 5, 6, 7, 10 по-настоящему определяют игру — потратьте время на них.
  4. Сразу возражайте на невозможные ответы. Список того, чего не существует, — в конце pitfalls.md. В том же сообщении предложите ближайшую рабочую замену.
  5. Пропускайте то, что уже решено. Если пользователь описал игру в первом сообщении, не переспрашивайте, а подтвердите.
  6. После последнего блока напишите документ-проект и получите подтверждение до генерации чего-либо.

Блок 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; range, number, toggle и segmented — их постоянные алиасы (см. Схема формы). Числовые границы задаются полями 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-раннером движка (npm run sim), и все проверки контрактов придётся делать глазами в браузере. См. debugging.md.
  6. Какие сценарии отладочных прогонов пишем сразу (движение, стрельба, смерть/респаун, конец раунда, смена карты, голосование)? Сценарий — обычный JSON, формат в debugging.md.
  7. Реализуем ли GameClientDef::predicted_state (опционально, дефолт None) ради покомпонентного отчёта о расхождении предикта? Без него работает грубое сравнение по камере.

Соответствие ответ → артефакт ​

БлокПорождает
1package.json, scripts/build-game-manifest.js, id/title в обоих плагинах
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, чат-команды, клиентские modules.chat.params.messages, modules.vote.params
5gameConfig.playerKeys, клиентские modules.controls.keySetList, spectatorKeys, apply_input ядра, predictor.rs, раскладка PLAYER_STATE_LEN
6src/data/weapons.js, src/data/models.js, модули оружия ядра, onCoreEvent для своих событий
7src/config/snapshot.js, строки Rust build_snapshot_blocks, клиентские parts.gameSets
8gameConfig.panel + клиентские modules.panel, gameConfig.stat + клиентские modules.stat, src/config/sounds.js, gameConfig.soundCues, gameInform.list
9gameConfig.scripted, src/host/<Bot>Manager.js, createModules, чат-команда ботов, core/src/bots/
10src/data/maps/*.js, gameConfig.maps/currentMap/mapScale/mapSetId/mapsInVote, части карт
11клиентские modules.canvasManager.canvases, initIdList, styles, parts.bakedAssets, parts.componentDependencies
12решения по kind/class снапшота, timers.networkSendRate, дополнительные ключи снапшота для подбираемых предметов и целей, gameConfig.migration.midRound + покрытие GameSim::serialize + serializeState/restoreState модулей, шаг checkpointRestore в сценарии sim
13gameConfig.playerState.defaultState, записи состояния из onCoreEvent
14проекты vitest.config.js, тесты паритета core/src/client/predictor.rs, tests/, обвязка dev/, entries.wasmNode в манифесте, отладочные сценарии для npm run sim, необязательный predicted_state

vimp-engine 0.38.3 · vimp-engine-core 0.23.4 · create-vimp-game 0.5.7