Розробка базового контроллера гравця
Контроллер гравця — перший компонент, який пишеться у будь-якому проекті, і перший, який доводиться переписувати, якщо архітектура була обрана наспіх. «Базовий» не означає «простий»: добре спроектований контроллер для 3D-персонажа включає мінімум шість взаємодіючих систем — введення, детектування землі, управління velocity, стани, анімацію та камеру.
Вибір основи: CharacterController vs Rigidbody
CharacterController — кінематичний примітив Unity. Його метод Move(Vector3 motion) двигає капсулу з дозволом коллізій, але не бере участь у фізичному рушієві: на нього не діють сили, він не штовхає об'єкти Rigidbody (без кастомного коду) та не отримує імпульсів. Для більшості action-ігор це плюс: рух передбачуваний і не залежить від physicsStep.
Rigidbody — повноцінний фізичний об'єкт. Управління через velocity або AddForce дозволяє природні взаємодії зі світом: персонаж котиться по схилу, його штовхають вибухи, він взаємодіє з об'єктами Joint. Платою за це є складність управління: без правильного PhysicMaterial (frictionCombine = Minimum, dynamicFriction = 0 на капсулі) персонаж застрягає на рёбрах геометрії.
Практичне правило: CharacterController для платформерів та action-RPG, Rigidbody для ігор з фізично значимим середовищем (гонки, шутери з ragdoll-взаємодією, VR).
Структура коду контроллера
Типічна помилка — один монолітний PlayerController : MonoBehaviour на 800 рядків, де перемішані введення, фізика, анімація та логіка станів. Переиспользувати такий компонент неможливо.
Правильна декомпозиція:
-
PlayerInputHandler— читаєInput System(новий InputSystem черезPlayerInputкомпонент або напрямкуInputAction), пише у структуруPlayerInputData:moveDirection,jumpPressed,sprintHeld,aimPosition -
PlayerMovement : MonoBehaviour— читаєPlayerInputData, управляє переміщенням та velocity -
PlayerAnimationController : MonoBehaviour— читає velocity та стани, управляє параметрамиAnimator -
PlayerCameraController : MonoBehaviour— незалежно від руху персонажа, працює зCinemachine Virtual Camera
Дані між компонентами передаються через спільну структуру PlayerState або события — не через прямі посилання компонентів один на одного.
Детектування землі та управління прострибуванням
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.
Інтеграція з Animator
Animator керується через параметри, а не через прямі виклики Play(). Параметри оновлюються в PlayerAnimationController кожен кадр:
-
Speed(float) — величина горизонтального velocity, нормалізована до maxSpeed -
IsGrounded(bool) — з детектування землі -
VerticalVelocity(float) —velocity.y, використовується для blend між fall/jump анімаціями
Для локомоції використовується Blend Tree за параметром Speed: Idle → Walk → Run. Це плавніше, ніж три окремих стани з пороговими переходами, і не вимагає ручного налаштування умов переходу.
Для повороту персонажа в напрямку руху — Quaternion.RotateTowards(current, target, rotationSpeed * Time.deltaTime), не LookAt(): останній телепортує поворот за один кадр.
Камера: Cinemachine FreeLook
Для 3D TPS-контроллера CinemachineFreeLook з трьома ригами (Top, Middle, Bottom) — стандартний вибір. Камера слідує за CameraTarget — порожнім трансформом, який плавно слідує за персонажем через SmoothDamp. Це запобігає тремтінню камери при русі по нерівній геометрії.
CinemachineCollider extension дозволяє проникнення камери в геометрію — обов'язковий для будь-якої 3D-гри з закритими просторами.
Орієнтовні строки
| Складність | Склад | Строк |
|---|---|---|
| Простий 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 тижні |
Процес розробки
Починаємо з прототипу без анімацій: лише капсула, рух, прострибування, Camera Follow. Займає день і дозволяє нащупати feel управління до того, як аніматор вкладе час у риггінг. Після затвердження feel — інтеграція Animator, потім — edge cases: рухливі платформи, нахилені поверхні, переходи між сценами зі збереженням швидкості.





