1. Четыре роли

MC-VmV — Model, Command, ViewModel, View. Такое разделение помогает менять интерфейс, сохраняя игровые правила и способ работы с данными.

  • Model — данные и состояние игры: здоровье, содержимое профиля, выбранное снаряжение. Они существуют независимо от открытых окон.
  • Command — действие или запрос на изменение. Оно проходит через игровую логику и сервисы, которые проверяют условия и принимают решение.
  • ViewModel — подготовка данных для конкретного представления: текст, формат чисел, доступность кнопки, причина отказа. Она связывает действия пользователя с нужными запросами.
  • View — отображение и ввод: окно, кнопка, индикатор или другой визуальный элемент.

Например, здоровье хранится в игровых данных. Система боя изменяет его, ViewModel готовит значение для индикатора, а View показывает полоску. Замена полоски числом не меняет расчёт урона.

2. От действия до результата

Рассмотрим улучшение предмета через окно метагейма:

  1. Игрок нажимает кнопку во View.
  2. ViewModel формирует запрос на улучшение выбранного предмета.
  3. Command обращается к ProfileService. Тот проверяет запрос и либо изменяет профиль, либо возвращает отказ.
  4. Обновлённое состояние или результат отказа поступает в представление: меняются характеристики, баланс и доступные действия либо появляется пояснение.

ProfileService хранит кеш профиля и предоставляет API его изменения. Правила улучшения и проверка стоимости выполняются за этим API. Отображаемое состояние кнопки помогает игроку понять условия, но окончательное решение принимает сервис.

3. Несколько представлений одних данных

Баланс валюты может одновременно отображаться в магазине, инвентаре и верхней панели. У каждого экрана свои формат и расположение, а источник данных общий. После подтверждённой покупки все представления должны показать новый баланс.

То же разделение работает в коргейме: состояние паузы, настройки и катсцены можно показывать разными экранами. Смена оформления не должна менять игровые правила.

4. Как сохранить простоту

Роли не требуют четырёх отдельных классов для каждой кнопки или ToY. Достаточно ясно понимать, где находятся данные, кто вправе их менять и как результат попадает на экран.

  • Не храните единственную копию игрового состояния в UI.
  • Проверяйте запросы в сервисах и игровой логике, даже если интерфейс уже ограничивает ввод.
  • Оставляйте во ViewModel подготовку представления, а во View — отображение и обработку ввода.
  • При закрытии экрана освобождайте его подписки, сохраняя данные у их владельца.

Для проверки правил достаточно данных и команд; для проверки отображения можно подать подготовленное состояние. Это позволяет находить ошибки без запуска всего интерфейса и всей игры одновременно.

Разделение Model и View

MC-VmV - это responsibility map для разделения game logic и presentation.

Model и Command отвечают за gameplay state и behavior. ViewModel и View отвечают за presentation, input adaptation и engine-facing visualization.

Mature Model/View Separation

Разделять model и view нужно после prototyping stage, когда gameplay idea уже пережила проверку fun.

На раннем prototype stage допустимо держать gameplay logic и presentation ближе друг к другу, если это помогает быстрее проверить идею. После этого responsibilities нужно развести, чтобы game state не зависел от UI, animation, render components или случайных scene details.

Model & Command

  • M - Model - entities, data structs и data classes. Чистые gameplay data с methods для изменения state и serialization.
  • C - Command - use cases и system tick jobs. Business/gameplay logic, которая действует на один или несколько models и создает behavior.

Presentation

  • Vm - ViewModel - presenters и view update behaviours. View-coupled logic, которая готовит data для rendering, interpolation, animation и input adaptation.
  • V - View - framework components и render components. Реальный visualization layer: renderers, animators, UI, particles, audio и другие engine-facing presentation pieces.

What It Prevents

  • UI, который напрямую управляет core gameplay state.
  • Gameplay logic внутри animation events и render components.
  • View code, который невозможно заменить без переписывания model.
  • Model, который знает слишком много про camera, UI, particles или scene setup.

Critique Notes

MC-VmV и early clean architecture

  • Главный риск не в самом MC-VmV, а в буквальном восприятии MC-VmV как требования создавать отдельные classes/files для каждого слоя.
  • MC-VmV - это responsibility map, а не class generator.
  • M - чистые данные / state.
  • C - commands, которые консистентно меняют данные.
  • Vm - слой, который читает model и обновляет view или предоставляет данные для view.
  • V - сама view. В Unity это часто не отдельный class, а prefab setup и visual components: Renderer, UIImage, Animator, ParticleSystem, etc.
  • MC-VmV чаще подходит для Brick, UI, profile systems, inventory, economy, save/load, purchasing, больших gameplay subsystems или очень больших ToY.
  • Маленький ToY чаще является object на игровой карте и не обязан иметь полный split по files/classes.
  • M и C могут быть разделены на разные classes, если это profile/database/business logic.
  • M и C могут жить в одном class: fields сверху как state, public methods ниже как commands.
  • Для мелкого object MC, Vm и references на Unity view могут жить в одном file.
  • Это не нарушение архитектуры, если responsibilities видимы.
  • Простая gameplay entity может уйти в release одним file, если разделение только увеличит cognitive load.
  • Деление увеличивает количество частей и взаимодействий.
  • Цена деления должна быть ниже цены неделения.
  • Разделять files/classes нужно только когда это снижает общую сложность.
  • Mature model/view separation - это maturity target, а не требование к первой итерации каждой идеи.

Формулировки, которые можно перенести почти напрямую:

MC-VmV is a responsibility map, not a class generator.

Separate responsibilities first. Separate files only when it reduces complexity.

For small ToYs, MC, Vm and Unity View can live in one file or prefab. That is not a violation if responsibilities are visible.

V is often not another class. In Unity, V is usually the actual prefab setup: Renderer, Animator, UIImage, ParticleSystem and other visual components.

The cost of splitting must be lower than the cost of not splitting.

Все темы Flexy.Bricks\ToYs