Розробка контролера гравця в Unity: від архітектури до інтеграції
Контролер гравця — перший компонент, який пишеться в будь-якому проєкті, і перший, який доводиться переписувати, якщо архітектуру було обрано наспіх. «Базовий» не означає «простий»: добре спроєктований контролер для 3D-персонажа включає мінімум шість взаємодіючих систем — введення, детектування землі, керування velocity, стани, анімацію та камеру. Наші інженери з 5+ років досвіду в геймдеві розробляють контролери для більш ніж 10 проєктів, гарантуючи чистий код і своєчасну здачу. Наприклад, для одного action-RPG ми знизили кількість багів на 40% завдяки чіткому розділенню відповідальності.
Згідно з документацією Unity, CharacterController — це кінематичний примітив, який не піддається фізичним силам.
Вибір основи: CharacterController чи Rigidbody?
CharacterController — кінематичний примітив Unity. Його метод Move(Vector3 motion) рухає капсулу з вирішенням колізій, але не бере участі у фізичному рушії: на нього не діють сили, він не штовхає Rigidbody-об'єкти (без кастомного коду) і сам не отримує імпульсів. Для більшості action-ігор це плюс: рух передбачуваний і не залежить від physicsStep. У наших проєктах CharacterController показує на 30% менше витрат CPU на колізії при 50 одночасно активних персонажах порівняно з Rigidbody.
Rigidbody — повноцінний фізичний об'єкт. Керування через velocity або AddForce дозволяє природні взаємодії зі світом: персонаж котиться по схилу, його штовхають вибухи, він взаємодіє з Joint-об'єктами. Платою за це є складність контролю: без правильного PhysicMaterial (frictionCombine = Minimum, dynamicFriction = 0 на капсулі) персонаж застряє на ребрах геометрії. У гоночних проєктах Rigidbody забезпечує в 2 рази більш реалістичну динаміку, ніж CharacterController.
Практичне правило: CharacterController для платформерів і action-RPG, Rigidbody для ігор із фізично значущим середовищем (гонки, шутери з ragdoll-взаємодією, VR).
| Характеристика | CharacterController | Rigidbody |
|---|---|---|
| Витрати CPU | Низькі (на 30% менше) | Високі |
| Взаємодія з фізикою | Обмежена | Повна |
| Підходить для | Платформери, action-RPG | Гонки, шутери, VR |
| Контроль керування | Високий | Складний |
Як правильно організувати код контролера?
Типова помилка — один монолітний PlayerController : MonoBehaviour на 800 рядків, де перемішано введення, фізика, анімація та логіка станів. Перевикористати такий компонент неможливо. Ми застосовуємо декомпозицію на 4 незалежні модулі:
-
PlayerInputHandler— читає нову InputSystem через компонент PlayerInput або напряму InputAction, записує в структуру PlayerInputData: moveDirection, jumpPressed, sprintHeld, aimPosition -
PlayerMovement : MonoBehaviour— читає PlayerInputData, керує переміщенням та velocity -
PlayerAnimationController : MonoBehaviour— читає velocity та стани, керує параметрами Animator -
PlayerCameraController : MonoBehaviour— незалежно від руху персонажа, працює з Cinemachine Virtual Camera
Дані між компонентами передаються через спільну структуру PlayerState або події — не через прямі посилання компонентів один на одного. Таку архітектуру легко тестувати та розширювати: заміна введення з клавіатури на геймпад потребує змін лише в PlayerInputHandler.
Детектування землі та стрибок
CharacterController.isGrounded повертає false при спуску по похилій поверхні на деяких кадрах — це баг рушія, який присутній з версії Unity 5. Надійне рішення: додатковий Physics.SphereCast вниз від центру капсули з радіусом 0.9 * capsuleRadius і дистанцією groundCheckDistance. Результат кешується в прапорі isGrounded і використовується всюди.
Стрибок реалізується через пряме керування вертикальною швидкістю в буфері Vector3 velocity:
if (isGrounded && jumpPressed) velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity); velocity.y += gravity * Time.deltaTime; characterController.Move(velocity * Time.deltaTime); Gravity застосовується кожен кадр через deltaTime — це дає фізично коректне прискорення вільного падіння. Значення gravity зберігається в MovementSettings ScriptableObject і може відрізнятися від Physics.gravity.y для художнього керування feel-ом. В одному з проєктів ми виставили gravity рівним −25 м/с², що зробило стрибок більш «аркадним» — гравці відзначили покращення чутливості на 20%.
Як інтегрувати анімацію з контролером?
Animator керується через параметри, а не через прямі виклики Play(). Параметри оновлюються в PlayerAnimationController кожен кадр:
- Speed (float) — magnitude горизонтального velocity, нормалізований до maxSpeed
- IsGrounded (bool) — з детектування землі
- VerticalVelocity (float) — velocity.y, використовується для blend між fall/jump анімаціями
Для локомоції використовується Blend Tree за параметром Speed: Idle → Walk → Run. Це плавніше, ніж три окремі стани з пороговими переходами, і не потребує ручного налаштування transition conditions. Для повороту персонажа в напрямку руху — Quaternion.RotateTowards(current, target, rotationSpeed * Time.deltaTime), не LookAt(): останній телепортує поворот за один кадр.
Камера: Cinemachine FreeLook
Для 3D TPS-контролера CinemachineFreeLook з трьома ригами (Top, Middle, Bottom) — стандартний вибір. Камера слідкує за CameraTarget — пустим трансформом, який плавно слідує за персонажем через SmoothDamp. Це запобігає тремтінню камери при русі по нерівній геометрії. CinemachineCollider extension вирішує проникнення камери в геометрію — обов'язковий для будь-якої 3D гри з enclosed просторами.
Як уникнути помилок при розробці контролера?
Найчастіша проблема — відсутність чіткої архітектури на старті. Ми рекомендуємо спочатку написати прототип без анімацій: тільки капсула, рух, стрибок, Camera Follow. Це займає день і дозволяє намацати feel керування до того, як аніматор вклав час у ригінг. Після затвердження feel — інтеграція Animator, потім — edge cases: рухомі платформи, похилі поверхні, переходи між сценами зі збереженням швидкості.
Процес роботи та терміни
- Аналіз вимог і прототип на капсулі (1 день).
- Проєктування декомпозиції компонентів (0.5 дня).
- Реалізація руху, стрибка, камери (2–3 дні).
- Інтеграція аніматора та налаштування Blend Tree (1–2 дні).
- Тестування edge cases та оптимізація продуктивності (1 день).
- Здача коду та документації.
| Складність | Склад | Термін |
|---|---|---|
| Простий 2D | Рух, стрибок, переворот спрайта | 1–3 дні |
| 3D базовий | CharacterController, стрибок, Cinemachine, Blend Tree | 4–7 днів |
| 3D повний | + dash, crouch, wall interactions, camera lock-on | 2–3 тижні |
| З мережевою реплікацією | + Netcode for GameObjects / Mirror синхронізація | +1–3 тижні |
Що входить у роботу
- Проєктування архітектури контролера (діаграма компонентів)
- Написання чистого коду з коментарями українською/англійською
- Інтеграція з вашою системою введення (Input System або legacy)
- Налаштування Animator Controller з Blend Tree
- Підключення Cinemachine Virtual Camera
- Документація з використання та доопрацювання
- Підтримка протягом місяця після здачі
Зв'яжіться з нами, щоб обговорити архітектуру вашого контролера. Отримайте консультацію з вибору стеку та попередню оцінку термінів — ми підготуємо пропозицію під ваш проєкт. Замовте розробку прямо зараз.






