InputBusSystem
Namespace: Vortex.Unity.InputBusSystem
Сборка: ru.vortex.unity.inputbussystem
Назначение
Управление вводом на основе Unity Input System с поддержкой карт ввода (Input Action Maps), подписки на экшены по принципу LIFO и прямой привязки клавиш.
Возможности:
- Централизованная маршрутизация сигналов ввода через статический контроллер
- Управление картами ввода с автоматической активацией/деактивацией по наличию подписчиков
- LIFO-маршрутизация — сигнал получает только последний зарегистрированный подписчик
- Гарантия парности
performed/canceled— отмена доставляется только получателю нажатия - Привязка произвольных клавиш и комбинаций к UI-событиям без прямого взаимодействия с Input System API
Вне ответственности:
- Ребиндинг клавиш в рантайме
- Визуальный редактор карт ввода (используется стандартный Unity Input Actions Asset)
- Аналоговый ввод (стики, триггеры) — только дискретные действия (Button)
Зависимости
| Зависимость | Назначение |
|---|---|
| Unity Input System | InputSystem.actions, InputAction, InputActionMap |
Vortex.Core.AppSystem |
App.GetState(), App.OnStateChanged, App.OnExit |
Vortex.Core.SettingsSystem |
Settings.Data().DebugMode — диагностическое логирование |
Vortex.Core.Extensions |
AddNew, AddOnce — хелперы коллекций |
Vortex.Unity.EditorTools |
[ValueSelector], [ClassLabel] |
Vortex.Unity.UI.Misc |
AdvancedButton — опциональная интеграция |
Архитектура
InputBusSystem/
├── InputController.cs # Статический контроллер: индексация, маршрутизация
├── InputSubscriber.cs # Модель подписчика с equality по Owner
├── Handlers/
│ ├── InputActionHandler.cs # Подписка на экшен через InputController
│ ├── InputMapHandler.cs # Активация карты ввода
│ └── KeyboardHandler.cs # Прямая привязка клавиш/комбинаций
└── Debug/
├── Model/SettingsModelExtInput.cs # partial SettingsModel + InputDebugMode
└── Presets/DebugSettingsExtInput.cs # partial DebugSettings + toggle
Поток данных
Unity Input System
↓ performed / canceled
InputController (маршрутизация по LIFO)
↓ callback
InputActionHandler / подписчик
↓ UnityEvent
UI / игровая логика
KeyboardHandler работает автономно — создаёт собственный InputAction в обход InputController.
Ключевые концепции
LIFO-маршрутизация
При нескольких подписчиках на один экшен performed доставляется только последнему (subscribers[^1]). Позволяет перехватывать ввод в модальных окнах и оверлеях без отписки предыдущих слоёв.
Парность performed/canceled
Объект, получивший performed, запоминается в CatchPerformed. При canceled сигнал доставляется только ему. Если верхний подписчик сменился — canceled отбрасывается.
Карты с подсчётом пользователей
Карта активируется при первом AddMapUser и деактивируется при уходе последнего пользователя (RemoveMapUser). Предотвращает конфликт между картами без ручного управления.
Комбинации клавиш
KeyboardHandler поддерживает до 3 модификаторов через композитные биндинги Unity (OneModifier, TwoModifiers, ThreeModifiers). Последняя клавиша в массиве — активирующая, остальные — модификаторы.
Отложенная подписка
Хэндлеры проверяют App.GetState() < AppStates.Running и откладывают регистрацию до готовности приложения через App.OnStateChanged.
Контракт
Вход
- Unity Input Actions Asset с определёнными картами и экшенами
AppStates.Running— состояние, при котором хэндлеры регистрируются
Выход
UnityEvent onPressed/onReleased— вInputActionHandlerиKeyboardHandlerAdvancedButton.Press()/Release()— опциональная интеграция- Активация/деактивация
InputActionMap— вInputMapHandler
Гарантии
- Один
performed→ максимум одинcanceledдля того же подписчика - Карта деактивируется только при нулевом количестве пользователей
- Подписчик не дублируется в списке (
AddOnceс equality поOwner) - Хэндлеры отписываются в
OnDisable/OnDestroy
Ограничения
- Только дискретный ввод (Button) — аналоговые значения не передаются
InputSubscriber.Equalsсравнивает поOwner— один объект не может иметь разные колбэки на один экшенKeyboardHandlerподдерживает максимум 3 модификатора; 4+ игнорируются с предупреждением- Нет механизма приоритетов — только порядок добавления (LIFO)
API
InputController (static)
// Карты ввода
static string[] GetMaps()
static void AddMapUser(string mapId, object inputMapUser)
static void RemoveMapUser(string mapId, object inputMapUser)
// Экшены ввода
static string[] GetActions()
static void AddActionUser(string actionInputId, object actionInputUser,
Action onPerformedCallback, Action onCanceledCallback)
static void RemoveActionUser(string actionInputId, object actionInputUser)
InputSubscriber
// Equality определяется по Owner
public readonly object Owner;
public Action OnPerformed { get; }
public Action OnCanceled { get; }
Использование
Подписка на экшен из кода
InputController.AddActionUser("Jump", this, OnJumpPerformed, OnJumpCanceled);
// Отписка
InputController.RemoveActionUser("Jump", this);
this используется как ключ идентификации. Повторный AddActionUser с тем же объектом не создаст дубликат.
Подписка через Inspector (InputActionHandler)
Компонент InputActionHandler на GameObject:
inputAction— экшен из dropdown (заполняется из Input Actions Asset)button— опционально, ссылка наAdvancedButtononPressed/onReleased— Unity Events
Активация карты (InputMapHandler)
Компонент InputMapHandler на GameObject:
inputMap— карта из dropdown
Карта активна, пока хотя бы один InputMapHandler для неё включён в сцене.
Прямая привязка клавиш (KeyboardHandler)
Компонент KeyboardHandler на GameObject:
buttonCode— массив отдельных клавиш (любая вызовет срабатывание)buttonsCombinations— массив комбинаций (последняя клавиша — активирующая, остальные — модификаторы)button,onPressed,onReleased— аналогичноInputActionHandler
Критические требования
- Input Actions Asset должен быть назначен —
InputController.Init()читаетInputSystem.actions. При отсутствии словари пусты, хэндлеры выбросятKeyNotFoundException. - Имена экшенов и карт уникальны — дубликат вызовет
ArgumentExceptionпри инициализации. KeyboardHandlerне проходит черезInputController— его экшены не участвуют в LIFO-маршрутизации.KeyboardHandlerтребует физической клавиатуры — приKeyboard.current == nullлогирует предупреждение.
Debug
Диагностическое логирование InputController управляется через Settings.Data().InputDebugMode; KeyboardHandler логирует под общим Settings.Data().DebugMode. Настраивается в ассете DebugSettings (toggle InputDebugMode).
При включении логируются: регистрация/отписка подписчиков, доставка performed/canceled, активация/деактивация карт.
Граничные случаи
| Ситуация | Поведение |
|---|---|
| Несуществующее имя экшена/карты | KeyNotFoundException |
RemoveActionUser для незарегистрированного объекта |
Тихий пропуск |
Подписчик performed удалён до canceled |
canceled отбрасывается |
Нет подписчиков при performed |
Тихий пропуск |
Keyboard.current == null |
Предупреждение; нажатия игнорируются |
| Комбинация с 4+ модификаторами | Предупреждение; комбинация пропущена |
OnEnable до AppStates.Running |
Подписка отложена до смены состояния |
| Input Actions Asset не назначен | Словари пусты; KeyNotFoundException при регистрации |