Создание платформера на Unity: механика и разработка
Выбор концепции платформера: что надо решить до кода
Чтобы платформер был не просто технодемкой, а полноценной игрой — нужно начать не с написания скриптов, а с ответов на ключевые вопросы. Unity даёт гибкость в реализации, но именно неопределённость на старте чаще всего ломает архитектуру игры в середине разработки.

Первое, что важно понять: какой именно платформер вы хотите сделать. Это не пустой вопрос жанра — от него зависят механика, интерфейс, физика и даже выбор методов оптимизации. Вот несколько базовых классификаций:
- По измерению: 2D, 2.5D, 3D. Для новичков логично начинать с 2D, но и 2.5D требует особого подхода к уровням и моделям.
- По игровой динамике: классический (как Super Mario), метроидвания (Hollow Knight), экшен-раннер (Rayman Legends), головоломка (Braid).
- По управлению: касание/тач (мобильные), клавиатура (ПК), геймпад (клауд-гейминг или консоль).
Перед созданием проекта, такого как создание платформера на юнити, задайте себе четыре комплекса вопросов:
- Какую драматургию и прогрессию уровней вы хотите? Пошаговое прохождение или открытый мир? Есть ли backtracking? Нужна ли карта?
- Какая основная механика в центре? Прыжок, смена гравитации, стрельба, взаимодействие со временем и т.д. Это определит кодовую архитектуру и привязку игровых объектов.
- Нужна ли физика “по-настоящему” или достаточно имитации? Например, платформер с тяжелыми объектами требует точной имплементации Rigidbody, а простой раннер — часто на кастомной логике.
- Какой будет масштаб уровней? От этого зависит, как проектировать сцену, разносить зоны загрузки и распределять коллайдеры.
Например: если вы задумали платформер в духе Metroidvania с вертикальными секциями, то камеру сразу нужно готовить к отложенному смещению, collision-based tracking, и управлению сценами с тегами-зоной. Другое дело — уровень Super Mario, где камера идёт по оси X и нигде не возвращается.
Ошибочно открывать Unity и начинать “на коленке” импровизацию. Лучше потратить 1–2 дня на написание документированной концепции: жанр, механики, условный набор уровней, контроль сложности, арсенал и протагониста. Эта работа окупит себя, когда проект станет масштабным.
Настройка проекта в Unity под платформер
Unity был создан для гибкости, но именно это играет против неопытного разработчика — лёгкость запуска вводит в заблуждение про лёгкость итоговой структуры. Поэтому настройка платформера требует жёсткой дисциплины с первого дня.
Прежде всего — выберите правильный шаблон проекта:
- 2D (URP): базовый выбор для двухмерного платформера. Использует упрощённое освещение, спрайты, фрейм-анимации и Tilemap.
- 3D (URP): выбор для 2.5D (где персонажи — 3D-модели, но движение ограничено по X и Y) или полностью трёхмерных платформеров.
Рекомендуется сразу структурировать проектную папку:
- Assets/Scenes: отдельная папка под все сцены (пример — Levels, Menus, Loading).
- Assets/Prefabs: UI, двери, платформы, враги, интерактивы.
- Assets/Scripts: разделение на системные скрипты (PlayerController, GameManager), UI и вспомогательные утилиты (например, Respawner).
- Assets/Animations, Assets/Sprites: по возможности — подкаталоги для каждого персонажа/объекта.
Почему важно начинать с минимально воспроизводимого уровня (MVP-уровня)? Потому что большая архитектура обманчива — кажется, что «всё почти работает», но на деле сломать можно любую механику сменой коллайдера. MVP должен содержать:
- Базовую землю с коллайдерами;
- Протагониста с контроллером;
- Одну подвижную платформу;
- Минимум одну камеру (желательно Cinemachine);
- Триггер на событие (смерть, переход в другую сцену, сбор предмета).
Фиксация уровня — это не просто сохранение сцены. Сразу задайте себе: какие элементы будут загружаться по мере прохождения, а какие статичны? Включите Gizmos, оптимизируйте Sorting Layers и Sorting Groups. Этот базовый уровень станет «эталоном», на нём будут отлаживаться механики и интерфейсы.
Совет: используйте пустые GameObject-и для логических группировок. Например, создайте в сцене объекты «Environment», «Enemies», «Items» и отслеживайте их отдельно — это поможет при Object Pooling и сборке финальной сцены.
Механика движения персонажа: ошибки и рабочие приёмы
Управляемость персонажа — центральное ощущение платформера. Именно здесь игрок принимает решение – «остаться или закрыть». Проблема в том, что стандартные компоненты Unity не дают «вкусного» ощущения: вроде бы всё работает, но персонаж «плавает», прыжки ощущаются как «похожие на прыжки, но не совсем». Разберёмся, почему так.
Первый соблазн — использовать CharacterController. Он хорошо себя показывает в 3D-action играх, но для платформеров его поведение чрезмерно «чистое» и лишено инерции. Коллизии плохо работают по диагонали, прыжки блокируются границами. Итог – анимация не бьётся с событиями, физика требует костылей.
Чаще всего используют один из двух подходов:
- Rigidbody + BoxCollider2D: хороший фундамент с встроенной физикой. Позволяет использовать отскок, платформы, столкновения с AI.
- Кастомная физика: движение через
transform.translateс ручной обработкой. Полный контроль, но требует построения коллизий и логики с нуля.
Решение — часто смешанный подход: Rigidbody используется как детектор столкновений, но передвижение не «сдаётся» Unity, а задаётся вручную через Setting Velocity. Это исключает влияние глюков физики, оставляя точный контроль реакции.
Теперь о “мелочах”, которые делают платформер лидером пользовательских оценок, а не посредственностью:
- Прыжковый буфер: игрок нажал прыжок на 3–5 кадров раньше, чем персонаж приземлился — прыжок активируется. Это снижает фрустрацию.
- Coyote time: персонаж может прыгнуть в течение 0.1–0.2 секунды после того, как соскользнул с платформы — как в мультике.
- Variable jump height: удержание кнопки прыжка даёт высоту, а короткое нажатие — минимальный подскок. Отзывчивость растёт.
- Early jump forgiveness: если игрок нажал прыжок чуть раньше, чем касание земли — движок «запомнит» и выполнит прыжок.
Для реализации часто используют State Machine. Это система, в которой состояния вроде Jumping, Falling, Grounded описываются как независимые сущности. Обработчики событий переходов можно привязать либо ко времени, либо к коллайдерам. Это избавляет от « if hell» в Update и упрощает читаемость.
Один из рабочих паттернов — Delayed Command Buffer: при нажатии клавиши прыжка команда не исполняется мгновенно, а кидается в очередь с TTL 0.2 сек. В функции FixedUpdate проверяется — разрешено ли прыгать. Если да — берем команду из стека.
Вот пример базового движения с Rigidbody2D и компонентами буфера:
if (Input.GetButtonDown("Jump"))
jumpBufferCounter = jumpBufferTime;
jumpBufferCounter -= Time.deltaTime;
if (isGrounded && jumpBufferCounter > 0)
{
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
jumpBufferCounter = 0;
}
Отдельное внимание — гашению скорости по оси X и переходам между действиями. Всегда задавайте граничные значения — Mathf.Clamp(velocity.x, -maxSpeed, maxSpeed) — чтобы избежать инерции при падении или столкновении с объектом.
Наконец, добавьте Debug.DrawRay в ноги персонажа: это поможет отслеживать «приземление» в реальном времени. Даже простое визуальное подтверждение того, что вы находитесь на земле, покажет, на сколько пикселей вы ошибаетесь в JumpTrigger’е.
Если ваш персонаж ощущается “пластиковым” или слишком “скользким” — вероятнее всего, проблема в:
- неправильной массе Rigidbody и drag
- игнорировании Time.fixedDeltaTime в расчетах
- отсутствии переходных состояний — Instant → Jump = плохо
Хорошее управление — не просто скорость и прыжок. Это комбинация: инерция, контроль высоты, буфер ошибок, сила отскока и базовая анимация, синхронизированная с событиями. Unity даёт все возможности сделать это “вручную” — но это работа, требующая планирования, отладки и тестов.
Камера в платформере: подходы и логика поведения
Поведение камеры — та деталь, которую пользователи почти не замечают, если она сделана грамотно. Но стоит допустить хотя бы небольшую ошибку — резкое движение, задержку или тряску — как всё управление начинает казаться «ломаным». В платформерах камера — не просто обозреватель, а активный участник, влияющий на ощущения от темпа, баланса и сложности.
При выборе стратегии камеры учитываются:
- Тип платформера: для «метроидвании» и открытых уровней важно постепенное раскрытие кадра, для автоплатформера — скролл с возможностью ускорения, для классики — следование с предсказуемыми ограничениями.
- Ритм сцены: в динамичных уровнях камера должна предугадывать движение, в головоломках — обрезать лишнее, фокусируясь на ключевом пространстве.
- Форма управления: мобильные игры часто подразумевают приближение, чтобы дать больше информации на экране на таче, в то время как ПК — дают более свободную обзорную зону.
На практике чаще всего используются три подхода:
- Жёсткое следование: камера привязана к позиции игрока. Быстро, просто — но очень «дешево» ощущается на ощупь. Особенно при быстрых остановках и прыжках.
- Смещение с зоной ожидания (dead zone): основа большинства профессиональных платформеров. Камера двигается лишь тогда, когда игрок выходит за зону допустимого смещения.
- Смарт-слежение с приоритетом направления: популяризирован в Rayman Legends и Hollow Knight. Камера не просто следует, но и заранее смещается в сторону текущего ввода или направления движения, делая геймплей кинематографичным.
Вот почему нельзя жестко привязывать камеру к координатам игрока. Это даёт резкие скачки, ломает анимации и сбивает расчёт траекторий прыжков. Лучшая стратегия — следование с интерполяцией и зазором (lerp + dead zone).
Unity предоставляет мощный инструмент Cinemachine, который избавляет от необходимости писать костыли. Конкретно для платформеров в 2D есть набор встроенных решений:
- CinemachineVirtualCamera — основной мозг следования.
- CinemachineFramingTransposer — позволяет задать dead zone, damping и offset камеры.
- CinemachineConfiner2D — ограничивает диапазон движения камеры в пределах полигона (например, ограничивает движение в пределах комнаты или уровня).
Пример реализации в сцене:
- Добавляем объект камеры с
CinemachineVirtualCamera. - Привязываем его к игроку (Follow Target = player).
- На компоненте
FramingTransposerнастраиваем:
- Soft zone шириной 20% и высотой 30% от экрана
- Damping по X и Y — около 0.3 для плавности перемещения
- Offset по Y — около 1.5, чтобы камера «смотрела вперёд»
- На сцене рисуем ограничивающий
PolygonCollider2Dи добавляем его вCinemachineConfiner2D.
Это даст «живую», предсказуемую и мягкую траекторию движения камеры. Используйте визуальное отображение зоны рамки и контура в режиме Gizmo — это даст понимание, как ощущения игрока зависят от параметров Framing.
Практическая рекомендация: тестируйте камеру на пустом уровне с перемещением по диагонали, лесенкам вниз и вверх, прыжкам со смещением. Именно здесь выявляются проблемы управления, даже если сам контроллер настроен идеально. Плохая камера ломает управление, а не только кадр.
Работа с уровнями: дизайн, сцены, загрузка
Платформер — это не только персонаж и враги, но и тщательно выверенные уровни. Разработка дизайна уровня начинается задолго до создания самой сцены. Ошибка, распространённая у новичков: тратить часы на рисование каждой платформы вручную. Это не масштабируется. Лучшее решение — модульный подход.
Unity предлагает для этого пленительный по возможностям инструмент: Tilemap с Grid System. Он доступен при создании 2D проекта и поддерживает:
- Рисование повторяющейся геометрии (плитка 16×16, 32×32 и т.д.)
- Auto tiling — автоматическая замена угловых и серединных элементов
- Разделение на слои (collision, background, foreground)
Вместо создания каждой стены вручную, дизайнер может разработать набор тайлов и рисовать уровни подобно Photoshop. Главное — заранее определить масштаб: если делать камеру в один экран, то 1 единица = 1 тайл (например, 1 Unity юнит = 32 пикселя).
При переходе между уровнями возникает классическая проблема: загрузка и состояние игрока. Многие решают её через статические переменные или одиночки (Singletons), однако универсальный способ — использовать контроллер «GameManager», который не уничтожается между сценами:
DontDestroyOnLoad(gameObject);
Дополнительно можно создать PlayerStats и LevelManager, которые хранят текущую позицию на карте, количество жизней, оружие и пройденные уровни.
Интересный паттерн — использовать пустые объекты с тегами «LevelEntry A», «LevelEntry B» — и на сцене при её загрузке игрок телепортируется в заранее определённую зону.
Совет по структуре большого проекта:
- Выделять отдельные сцены не только под уровни, но и под фоны, отдельные боссы, UI-модули
- Такие сцены можно загружать в фоне через
SceneManager.LoadSceneAsync(..., LoadSceneMode.Additive). - Благодаря Additive сценам, можно переиспользовать объекты на нескольких уровнях без их дублирования.
Чтобы снизить нагрузку на память — используйте объединённые префабы секций. Например, лестница — не составляется из тайлов, а собирается в Prefab «Ladder_5m». Это упрощает модификации, ускоряет сцену и даёт единый контроль высоты и поведения.
Как заранее заложить “скелет” кампании?
- Создайте Excel/Google таблицу с уровнями, их условиями, ключевыми объектами (враги, ловушки, уникальные механики).
- Пропишите связи — откуда происходит вход, куда ведёт выход.
- Задайте “ось сложности” — простой → усложнение → кульминация → развязка.
Простой редактор состояния кампании помогает не запутаться, особенно если игра состоит из более чем 5-7 сцен с взаимодействием. Многие разработчики используют Unity Timeline и Visual Scripting, но часто обычная текстовая структура быстрее и управляемее.
Правило: каждый уровень должен тестироваться как отдельный юнит — сразу после завершения ищите deadzones, вылеты за экран, неправильные триггеры и ошибки слоев. Позже, при объединении уровней, эти мелочи умножаются.
Именно сцены и их организация являются той структурой, которая повышает или уроняет производительность платформера. Продуманная система загрузки сцен, повторяемых префабов и модификации через ScriptableObjects — облегчит тестирование, модификации и оптимизацию игры в будущем.
Враги, ловушки и взаимодействие с окружением
После того как базовая механика движения и уровни готовы, приходит очередь оживить мир — добавить врагов, ловушки, объекты взаимодействия. Здесь важно соблюсти баланс: не навалить десятки систем, а построить универсальные паттерны поведения, которые можно масштабировать.
В основе AI для платформера — не вычисления маршрутов через A*, а проще: распознавание зон, реакция на позицию игрока, выполнение простых паттернов. Например, враг, который двигается влево-вправо, поворачивается при входе в триггер, наносит урон при столкновении и проигрывает анимацию смерти — это уже достаточная боевая единица для большинства уровней.
Пример простого паттерна поведения врага:
- Враг движется с постоянной скоростью;
- При столкновении с “EdgeTrigger” или стеной — разворачивается;
- Если игрок входит в зону Aggro (триггер), переключается на преследование;
- Если расстояние > X — враг возвращается к патрулированию;
- При попадании в «удар» — воспроизводит анимацию смерти и уничтожается.
Для реализации такой логики можно использовать State Machine / Behaviour Tree, но чаще хватает простого кода на FixedUpdate с проверкой дистанции. Главное — строго разделять:
- Физику столкновений (Physics2D.OverlapCircle, бокс-коллайдеры)
- Логику поведения (флаги состояния: patrolling, chasing, dying)
- Активацию действий (триггеры, timers, анимации)
Вот фрагмент кода простого поведения врага:
if (playerInRange && !isDead) {
Vector2 direction = player.position - transform.position;
rb.velocity = new Vector2(direction.normalized.x * speed, rb.velocity.y);
} else if (!isDead) {
rb.velocity = new Vector2(patrolSpeed * facingDirection, rb.velocity.y);
}
Важно использовать LayerMask для определения контактов. Объекты с тегом «Player» должны иметь отдельный layer, чтобы не путаться с платформами и проектами UI. Это делает столкновения предсказуемыми.
Атаки и взаимодействие организуются через Event-систему или простые OnCollisionEnter2D:
void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.CompareTag("Player")) {
collision.gameObject.GetComponent<PlayerHealth>().TakeDamage(damage);
}
}
Или, если используется триггер-зона под ловушку:
void OnTriggerEnter2D(Collider2D other) {
if (other.CompareTag("Player")) {
StartCoroutine(ActivateSpikes());
}
}
Платформеры, особенно головоломочно-ориентированные, сильно выигрывают от грамотно реализованных ловушек и интерактивов:
- Давящие потолки с задержкой;
- Платформы, исчезающие после касания;
- Лифт-зоны, активирующиеся кнопкой;
- Зоны безгравитации, создающие смену управления;
- Рассыпные полы, реагирующие на стояние игрока.
Каждый механизм логично выносить в отдельный скрипт по принципу SRP (Single Responsibility Principle). Это делает поведение модульным и быстро адаптируемым к новым условиям в уровнях.
Для улучшения наглядности — используйте Gizmos: рисуйте зоны триггеров, направления патрулей, временные линии. Это особенно критично при плотной архитектуре уровня, где ошибки в позиционировании могут не сразу быть очевидны.
При создании анимаций врагов стандартизируйте состояния: Idle, Move, Attack, Hit, Die. Используйте Animator Controller с параметрами Speed, Health, IsDead и переключайте их через скрипт. Это мощный способ синхронизации логики и визуала.
Нюанс: смерть врагов не всегда = Destroy(). Чтобы избежать проблем c Object Pooling (перечитаем позже), уместно реализовать деактивацию через SetActive(false) и возврат в пул.
Наконец, не забываем про «экосистему обратной связи»: звук попадания, вспышка удара, эффект разрушения. Это не только эстетика — это механика, подтверждающая действие. Без неё игрок ощущает «пустоту» даже при победе.
Оптимизация механик на раннем этапе
В платформере мало что может вызвать серьёзные просадки FPS — уровни относительно малы, графика проста. Но казалось бы незначительные вещи — количество активных объектов, сложные триггеры, постоянные расчёты в Update — незаметно убивают производительность, особенно на мобильных.
Начнём с первого ресурсоёмкого аспекта: управление объектами вне экрана. Unity по дефолту не отключает объекты за пределами камеры. Они продолжают обрабатывать скрипты, физику, анимации. Решение — использовать OnBecameVisible и OnBecameInvisible для активирования/деактивации:
void OnBecameInvisible() {
enabled = false;
}
void OnBecameVisible() {
enabled = true;
}
Лучше — завести отдельный компонент VisionHandler, который будет включать/выключать AI и физику при появлении во фрейме рендера.
Следующий шаг — Object Pooling. Любой враг, платформа, снаряд, который появляется и исчезает, не должен каждый раз инстанцироваться и уничтожаться. Это приводит к фрагментации памяти и скачкам. Вместо этого создаётся пул — набор заранее подготовленных объектов, которые активируются, используются и возвращаются в неактивное состояние.
Unity 2021+ предлагает встроенный ObjectPool API, но можно использовать и собственный метод:
- Создаётся List<GameObject>, содержащий все заготовленные объекты;
- На старте они инициализируются и скрываются;
- При необходимости достаются из пула и активируются;
- Когда «умирают» — возвращаются в пул.
Такой подход особенно эффективен для врагов и снарядов босса, которые массово появляются на сцене.
Третий аспект — сорсинг и сортировка объектов. В 2D платформере Sorting Layers решают весь порядок отрисовки: без них можно легко столкнуться с ситуациями, где персонаж проваливается визуально «под» платформу или мешается с UI. Рекомендуется структура:
- Background
- Geometry
- Player
- Enemies
- Particles
- UI
Каждая категория получает Sorting Layer и порядок внутри (Order in Layer). Даже один ошибочно выставленный спрайт может испортить визуал основной механики. Установите правила: игрок всегда — 50, враги — 45, платформа — 10 и т.п.
В 2.5D/3D — дополнительный фактор: освещение и тени. Легко забыть, что единичный источник тени на каждые 10 объектов уже даёт просадку FPS. Используйте Baked Lighting, если свет статичный, и отключайте тень на второстепенных объектах (Cast Shadows = Off, Receive Shadows = False).
Последние 3 лишних потребителя:
- Компоненты Animator с включёнными всеми слоями, даже если они неактивны
- Update без проверки — даже простой пустой скрипт на 1000 объектов потребляет CPU
- Использование физических триггеров вместо логических флагов, если точность не критична
Оптимизация не должна быть последним этапом. В платформере её лучше проектировать параллельно: правило — не больше 50 активных объектов на экране одновременно, все действия за пределами камеры деактивированы, никаких постоянных удалений и инстанцирований во время геймплея.
