Проектування боєвих систем і механік взаємодії
Боєва система ламається не там, де її проектують — вона ламається у стику між анімацією, hitbox і логікою нанесення урону. Типічна картина: дизайнер розставив вікно атаки в Animation Event на кадрі 12, програміст читає його в OnAttackHit(), а QA знаходить, що удар проходить крізь ворога при fps нижче 30 — тому що Physics.OverlapSphere викликається рівно один раз у момент події, і коллайдер ворога між кадрами не перекривається з hitbox.
Архітектура hitbox-системи
Професійна реалізація розділяє hurtbox (область, яку можна поцілити) і hitbox (область, якою персонаж атакує). Обидві — окремі коллайдери на дочірніх об'єктах, керовані через компоненти Hurtbox : MonoBehaviour і Hitbox : MonoBehaviour.
Hitbox активується не через SetActive(), а через перемикання isTrigger і слою — це дешевше за продуктивністю при частих вкл/вимк. За одну атаку hitbox повинен потрапити в кожну hurtbox лише один раз: це контролюється через HashSet<int> з InstanceID уже поражених цілей, який очищується при деактивації hitbox.
Для зброї ближнього бою з швидкими рухами OverlapSphere за один кадр недостатньо. Надійніше Physics.CapsuleCast від позиції зброї на попередньому кадрі до поточної — це ловить цілі, які опинилися у траєкторії руху клинка між кадрами. previousPosition зберігається в LateUpdate() попереднього кадру.
Управління станами бою
Кінцевий автомат боєвих станів — це не Animator State Machine. Animator управляє візуалом; ігрова логіка живе у окремому CombatStateMachine. Стани: Idle, Attacking, Recovering, Staggered, Blocking, Parrying. Кожен стан — окремий клас з Enter(), Update(), Exit().
Пріоритет скасування атак (cancel priority) — одна з найскладніших частин. У файтингах та action-RPG гравець повинен мати можливість скасувати частину анімації атаки в dash або наступний удар. Це реалізується через cancelWindows[] — масив структур з startFrame, endFrame, allowedCancels. Коли нормалізований час Animator потрапляє у вікно, прапор canCancel піднімається, і CombatStateMachine приймає новий введення.
Системи взаємодії: інтерактивні об'єкти і діалоги
Компонент взаємодії будується за схемою Interactable / Interactor. IInteractable — інтерфейс з методом Interact(GameObject interactor). InteractorComponent на гравцеві тримає List<IInteractable> у радіусі дії, оновлюваний через OnTriggerEnter/Exit. При натисканні кнопки викликається closest.Interact(gameObject).
Частої помилки — реалізувати взаємодію через Raycast в Update() кожен кадр. Це і зайві розрахунки, і проблеми з пріоритетом при кількох об'єктах у лучі. Trigger-зона з OverlapSphere раз на 0.1 секунди через InvokeRepeating дешевша і надійніша.
Для діалогових взаємодій важлива черга подій. Якщо під час діалогу гравець ще раз натискає кнопку, наступний Interact не повинен оброблятися до закриття поточного. Прапор isInteracting в InteractorComponent блокує нові взаємодії — і знімається через подію OnInteractionComplete.
Баланс відповіді та читаємості
Feedback на поцілення критичне для feel боївки. Мінімальний набір: hitpause (зупинка анімації атакуючого на 2–4 кадри при поціленні), screen shake через CinemachineImpulse, звуковий ефект з варіацією pitch. Hitpause реалізується через тимчасове встановлення animator.speed = 0 і Time.timeScale не чіпається — це важливо, якщо є UI або інші системи.
Damage numbers — окрема розмова. Floating text з TextMeshPro повинен інстанціюватися з pool, а не через Instantiate() кожен удар. При активній боївці з AoE атаками без pool легко отримати 50+ інстанціювань на секунду і GC spike.
Орієнтовні строки
| Масштаб | Склад | Строк |
|---|---|---|
| Базовий | Одна атака, hurtbox/hitbox, HP-компонент | 3–6 днів |
| Середній | Combo система, блок, парирування, i-frames | 2–3 тижні |
| Розширений | Кілька видів зброї, здібності, статус-ефекти | 4–6 тижнів |
| Повна система | Мережева синхронізація боювання, rollback netcode | 2–4 місяці |
Процес проектування
Починаємо з таблиці станів і переходів у документі — перш ніж писати код. Кожен стан, кожен перехід, умова і пріоритет. Це розкриває конфлікти ще на етапі дизайну: наприклад, що відбувається, якщо гравець отримує урон у момент парирування — stagger або ні?
Потім — прототип з placeholder-анімаціями (навіть кубами) для перевірки тайміну вікон атаки і cancel-системи. Інтеграція з реальними анімаціями — останній етап, не перший.





