Artean

Создание мобильной игры на Unity: примеры и этапы

Почему Unity — оптимальный выбор для мобильных игр

Unity — один из немногих движков, объединивших в себе масштабируемость, гибкость и простоту, достаточную даже для первого проекта, который реально довести до релиза. Создание мобильной игры на Unity выгодно отличается от работы с другими движками: в отличие от Unreal Engine, больше ориентированного на графически насыщенные проекты, Unity не перегружен системами, не нужными мобильной игре. Godot подходит для небольших 2D-экспериментов, но пока что страдает от недостатка поддержки и зрелой экосистемы.

Создание мобильной игры на Unity: пошаговое руководство с примерами

Платформа поддерживает Android и iOS из коробки: прямо из одного интерфейса вы можете собирать .apk и .ipa-файлы. Встроенные инструменты импорта SDK, настройка ориентации экранов и плотностей пикселей уменьшают количество ручной работы. Это особенно важно, когда вы хотите быстро получить рабочий билд для тестирования. Кроме того, Unity — кроссплатформенный: один и тот же проект играет одинаково на смартфоне, планшете или в WebGL-версии на сайте.

Asset Store — это ключевой актив. Механика свайпа, генератор уровней, заготовка UI — всё это покупается (или скачивается бесплатно) и адаптируется под проект. Компонентная архитектура позволяет добавлять или отключать функции по необходимости. Даже при первом опыте разработки вы можете создать работающий проект с игровым процессом, прогрессией и меню, не написав тысячу строк с нуля.

Но Unity не лишён ограничений. Если цель — гиперкачественная 3D-игра с рейтрейсингом и обилием VFX, оптимизация под смартфоны потребует серьёзной переработки. Или если ваша задача — минимальный билд под веб с размером менее 5 МБ, Unity может быть «тяжеловат» из-за зависимости от C#-рантайма.

Пример: один человек может сделать за 5 дней простую 2D-аркаду — клон Flappy Bird или Match-3 с базовой системой очков. Движок предоставляет физику, обработку касаний, текстуры, систему сцен, переходов между ними и даже поддержку рекламы через встроенные плагины.

Что нужно решить до начала разработки (архитектура идеи)

Игра — это не набор скриптов, а целостный проект с избранным жанром, режимами игры, визуальным стилем, аудиторией и каналами дистрибуции. Решения на этом этапе определяют: какие механики вы реализуете, хватит ли ресурсов, и будет ли ваш файл играться на дешёвом Android-смартфоне так же, как на iPhone 13.

Жанр: фундамент для конструктора вашей игры

Выбор жанра — это не просто «будет платформер». Это определяет поведение игроков, подход к монетизации и интерфейс. Например:

  • Hyper-casual (сплитер, раннер, кликер) — короткие сессии, минималистичный UI, высокая частота рекламы. Простая механика повторяется много раз.
  • Mid-core (карточные бои, tower defense, RPG) — требуют систем прогрессии, баланса игровых характеристик, кучи UI-компонентов.
  • Match-3 или puzzle — сильная зависимость от контента, уровней, а не только механики. Используется генерация карт или дизайнер из уровней.

Жанр влияет даже на ритм скриптов в игре: кликеры работают по интервалам, шутеры — на кадровой синхронизации, головоломки — по «ходам» игрока.

Графика: 2D или 3D — это не просто вкус

2D-игра быстрее в разработке и потребляет меньше ресурсов. Вам достаточно спрайтов, Canvas-интерфейса и минимального количество кодов для движений. 3D-проект потребует сложных моделей, освещения, камеры, физики и, чаще всего, проблем с производительностью. Даже у мощных смартфонов draw call’ы в Unity могут «падать» на обилии объектов.

Базовый ориентир — если вы делаете игру с фронтальной камерой (при виде сбоку), выбирайте 2D. Если планируется свободное перемещение по сцене, применим 3D.

Платформы и устройства: ограничения, которые нельзя игнорировать

Минимальный уровень Android SDK (обычно от API 21 для 95% устройств). Разрешение экрана варьируется от 480×800 до 2560×1440+, и если не тестировать ширину пикселизации, интерфейс съезжает. ОЗУ и процессор зависят от класса устройства: low-end теряет кадры при анимации UI, если вы используете нескомпрессированные текстуры.

Проверка идеи через аналог: хотите сделать аналог Subway Surfers? Вам потребуется:

  • 3D-анимации с автоматической генерацией препятствий
  • Поддержка динамического ландшафта
  • Фиксированная камера со скриптом следования
  • Система разблокировки героев / бонусов (т.е. файловая система для прогресса)

Проверить реальность проекта можно буквально за 30 минут: нарисуйте набросок экрана, опишите механику словами и примерьте это под палец на смартфоне. Если управление выглядит сложно — стоит упростить.

Не пишите код, пока не решили это

Главная ошибка новичков — старт скриптов без продуманной архитектуры. В результате проект превращается в сочетанную кашу из вызовов Update, событий, случайно связанных переменных. Стратегия «сыграем, посмотрим» работает только в геймдизайне, но не в коде.

Сначала ответьте себе:

  • Что запускается первым? (Меню, туториал, уровень?)
  • Как сцены связаны между собой?
  • Есть ли необходимость в системе сохранений?
  • Какие данные переходят между сценами?

Установка Unity и настройка окружения под мобильную разработку

Работать с Unity без корректной среды — всё равно что собирать мебель без отвертки. Начать стоит с установки Unity Hub — официального лаунчера, где вы можете управлять проектами, версиями и плагинами под Android/iOS.

Выбор правильной версии

Для мобильной разработки лучше использовать LTS-релиз (Long Term Support), который обновляется без радикальных изменений. Например, Unity 2022.3 LTS — стабильна, совместима со всеми ключевыми пакетами и предоставляет поддержку минимум 2 года. Актуальные версии могут иметь критические ошибки или несовместимости с Android SDK.

Пошаговая настройка:

  1. Скачайте Unity Hub и установите LTS-релиз с модулями Android Build Support и iOS Build Support.
  2. Создайте проект, выбрав шаблон 2D или 3D в зависимости от концепта.
  3. Перейдите в File → Build Settings, выберите Android или iOS.
  4. Для Android — убедитесь, что установлен Android SDK & NDK. Unity предлагает автоматическую установку, но иногда лучше задать путь вручную.
  5. Для iOS (macOS only) — наличие Xcode обязательно (минимум версии 14).

Типичные проблемы новичков при сборке:

  • Android build failed — чаще всего отсутствует либо SDK, либо исправные пути к нему. Решается указанием вручную: Edit → Preferences → External Tools.
  • Could not produce a signed APK — не создан ключ подписи. Для теста можно использовать debug-ключ, но в Play Store нужен production-ключ.

Один раз правильно настроенная сборка экономит десятки часов в будущем. Сохраняйте пути и конфигурации в IDE-шных .json-файлах, чтобы не настраивать каждый раз заново.

Построение базовой структуры мобильной игры

Ошибочно воспринимать игровой проект как цепочку сцен или набор единичных скриптов. Для стабильной и масштабируемой мобильной игры на Unity необходимо задать архитектуру с чётким разделением ответственности между системами, а не писать всю логику в Player.cs. В этом разделе рассмотрим, как правильно «скелетировать» игру: выбрать сцены, менеджеры, UI-компоненты и подготовить проект к расширению без хаоса в коде.

Из чего состоит базовая структура мобильной игры

Мобильная игра, вне зависимости от жанра, как правило, состоит из следующих элементов:

  • Game Manager — центральный контроллер, запускающий логику уровня, отслеживающий состояние игры, переходы, инициализацию.
  • UI Manager — система управления интерфейсом, отвечающая за отображение очков, различных окон, паузы и экрана проигрыша.
  • Scene Loader — отдельный скрипт, обрабатывающий переходы между сценами без дублирования кода.
  • Spawn System (если применимо) — отвечает за генерацию платформ, врагов, бонусов или других игровых объектов.
  • Input Manager — изолирует управление: свайпы, касания, удержания экрана.

Каждая из этих систем находится в своём скрипте или даже «слое» префабов. Это упрощает отладку: если вы замечаете сбой при респавне врагов, не нужно разбираться в UI-логике. Нарушение этих границ — частая причина сложных багаутов: всё работает странно, но непонятно где.

Структура, которую можно взять за основу

Допустим, вы разрабатываете 2D-раннер. Структура папок и компонентов может выглядеть следующим образом:

  • Scripts/ManagersGameManager.cs
  • UIManager.cs
  • SceneLoader.cs
  • Scripts/GameplayPlayerController.cs
  • ObstacleSpawner.cs
  • ScoringSystem.cs
  • UI/PrefabsHUDCanvas.prefab
  • ButtonStart.prefab
  • PauseMenu.prefab
  • ScenesMainMenu.unity
  • GameScene.unity
  • GameOver.unity

Такой подход не просто упрощает чтение проекта в Unity, но и уменьшает когнитивную нагрузку: вы знаете, где искать проблему.

Раздельная логика: почему избегать «монолитных» скриптов

Один из распространённых анти-паттернов — вложить всё внутрь Player.cs: обработку касания, движение, обновление UI, проверку столкновений. В краткосрочной перспективе это работает, но любой апдейт превращается в часы исправлений, ведь каждое изменение цепляет остальное.

Правильная стратегия — делить логику на модули и использовать события. Например, при касании игрока объект может сработать триггер, отправив Event в GameManager, который увеличивает счёт и обновляет UI через UIManager. Один каскад, но всё по слоям.

Поддержка экранов и адаптация под плотности пикселей

Одна из самых недооценённых, но критичных задач — обеспечение корректного отображения интерфейса на всех современных девайсах. От iPhone SE до Xiaomi Redmi Note 12.

Unity Canvas предлагает следующие режимы рендеринга:

  • Screen Space – Overlay — по умолчанию. Удобен в простых проектах.
  • Screen Space – Camera — даёт больше контроля при масштабировании элементов, особенно в 3D.

Добавьте к Canvas компонент Canvas Scaler и используйте режим Scale With Screen Size. Рекомендуемые параметры:

  • Reference Resolution: 1080×1920
  • Match (Width or Height): 0.5 — сбалансированный компромисс

Это решение позволяет избежать ситуации, когда кнопка «Начать игру» уезжает за пределы экрана на маленьких устройствах или визуально крошечна на планшетах.

Мини-пример: стартовая сцена с кнопкой «Начать игру»

  1. Создайте новую сцену MainMenu.unity
  2. Добавьте Canvas, задайте Canvas Scaler → Scale With Screen Size
  3. Добавьте UI → Button, назовите её StartButton
  4. Создайте скрипт MainMenuController.cs:
using UnityEngine;
using UnityEngine.SceneManagement;

public class MainMenuController : MonoBehaviour
{
    public void StartGame()
    {
        SceneManager.LoadScene("GameScene");
    }
}
  1. Назначьте этот скрипт на пустой GameObject
  2. На кнопке в OnClick добавьте ссылку на этот объект → метод StartGame()

Теперь при нажатии кнопки сцена переключится — без одной строки лишнего кода в другом месте.

Реализация ключевой механики (игровой процесс: шаг за шагом)

Теперь — к самому важному: сделать так, чтобы игрок чувствовал контакт с игрой. Независимо от жанра, вы реализуете сбор ввода, динамику объектов, взаимодействие между ними и логику результата (победа/поражение). Здесь мы разберём базовый пример endless runner с боковым видом: та же механика, что в Subway Surfers или Jetpack Joyride.

Игровой цикл в Unity: основная логика

Unity предоставляет событийные методы, на которых строится логика:

  • Start() — инициализация объекта
  • Update() — вызывается каждый кадр (~60 раз в секунду)
  • FixedUpdate() — вызывается с фиксированной частотой, применим для физики
  • OnCollisionEnter2D/3D — обработка столкновений

Все они работают внутри MonoBehaviour, но важно: избегайте загромождения большого количества логики в Update() одного объекта. Лучше передавайте события через делегаты или UnityEvents.

Пример: реализация endless runner на минимуме

Основные составляющие:

  • Игрок — перемещается по вертикали (прыжки) или дорожкам (влево/вправо)
  • Препятствия — движутся навстречу игроку
  • Очки — увеличиваются по времени или за преодоление препятствий

Создадим скрипт для авто-передвижения игрока:

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float jumpForce = 7f;
    private Rigidbody2D rb;
    private bool isGrounded = true;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0) && isGrounded)
        {
            rb.velocity = Vector2.up * jumpForce;
            isGrounded = false;
        }
    }

    private void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.CompareTag("Ground"))
            isGrounded = true;
    }
}

Объекты-платформы и пол помещаются на слой Ground. Игрок распознаёт столкновение и разрешает повторный прыжок.

Спавн препятствий в сцене

Создайте скрипт ObstacleSpawner.cs с автогенерацией объектов через интервалы времени:

using UnityEngine;

public class ObstacleSpawner : MonoBehaviour
{
    public GameObject obstaclePrefab;
    public float spawnRate = 2f;
    private float timer = 0f;

    void Update()
    {
        timer += Time.deltaTime;
        if (timer >= spawnRate)
        {
            SpawnObstacle();
            timer = 0f;
        }
    }

    void SpawnObstacle()
    {
        Instantiate(obstaclePrefab, transform.position, Quaternion.identity);
    }
}

Этот скрипт размещается на точке за пределами видимости справа, чтобы препятствия появлялись и двигались внутрь камеры. Для движения препятствий добавьте к prefab’у простой скрипт:

public class MoveLeft : MonoBehaviour
{
    public float speed = 5f;

    void Update()
    {
        transform.Translate(Vector2.left * speed * Time.deltaTime);
        if (transform.position.x < -15f)
            Destroy(gameObject);
    }
}

Это решение обрабатывает 95% случаев для начала. Вы можете впоследствии добавить выборку препятствий из массива, инкрементальную скорость, уровни сложности.

Разделение механики и визуала

Даже если кажется, что проще объединить анимацию и действие — не делайте этого. Например, когда игрок сталкивается с препятствием, пусть физика обрабатывает это, а GameManager только реагирует: отправляет сигнал проигрыша, запускает анимацию, останавливает спавн. Отделение слоёв — гарантия, что вы можете заменить визуальную часть без переписки логики.

Отладка: как диагностировать поведение

  • Debug.Log() — непревзойдённо простой инструмент. Помечайте ключевые действия: прыжок, столкновение, удаление объекта.
  • Gizmos — используйте для отрисовки границ коллайдеров и движения объектов в редакторе.
  • Time.timeScale = 0.1f — замедление времени на этапе теста поможет точно отследить момент ошибки.
  • Colliders без Rigidbody — частая причина «не работающих» столкновений.

Интеграция UI и системы прогресса

Пользовательский интерфейс в мобильной игре — не просто надстройка, а активный участник игрового цикла. HUD-индикаторы, менюшки, пауза, всплывающие окна после проигрыша — всё это требует внимания не меньше, чем механика. Ошибки в UI кажутся «визуальными», но именно они чаще всего приводят к плохому опыту: нечёткий счёт, неактивная кнопка, неудобное меню. Здесь разберём, как построить UI-часть игры и подключить систему сохранения прогресса.

Конструкция стандартного интерфейса

  • HUD — во время игры показывает очки, здоровье, время, бустеры и т. д.
  • Pause Menu — вызывается кнопкой, содержит «продолжить», «выйти», «перезапустить»
  • Game Over Screen — появляется по проигрышу, сообщает результат, предлагает начать заново
  • Main Menu — стартовая сцена с кнопками «Играть», «Настройки», «Выход»

Каждая из этих частей оформляется как Canvas-панель с своими элементами. Для смены UI на сцене используйте активацию/деактивацию GameObject’ов, а не загрузку новых сцен — это быстрее и стабильнее.

Пример: добавим очки и логику HUD

  1. Добавьте на Canvas Text (или TextMeshPro Text) и назовите ScoreText
  2. Создайте ScoreManager.cs:
using UnityEngine;
using UnityEngine.UI;

public class ScoreManager : MonoBehaviour
{
    public Text scoreText;
    private int score = 0;

    public void AddPoint()
    {
        score++;
        UpdateUI();
    }

    void UpdateUI()
    {
        scoreText.text = "Очки: " + score.ToString();
    }
}

Вызывайте AddPoint() каждый раз, когда игрок проходит препятствие или выживает определённое время. UI всегда отражает текущее состояние логики, не хранит данные сам.

Управление паузой и выходом

При нажатии на кнопку «Пауза» вы можете остановить время в игре через:

public void PauseGame()
{
    Time.timeScale = 0f;
    pauseMenu.SetActive(true);
}

И аналогично:

public void ResumeGame()
{
    Time.timeScale = 1f;
    pauseMenu.SetActive(false);
}

Time.timeScale = 0 останавливает и физику, и анимации. Не забывайте включать/отключать UI-элементы отдельно.

Сохранение прогресса

Существует несколько способов сохрани́ть данные между сессиями:

  • PlayerPrefs — простой способ сохранить пары «ключ-значение», подходит для очков, настроек
  • JSON-файлы — для сложных структур (множество уровней, настройки игрока)
  • Serializable ScriptableObjects — продвинутый вариант, удобно использовать при конфигурировании игровых данных

Пример: сохранение наибольшего результата через PlayerPrefs

void SaveHighScore(int score)
{
    if (score > PlayerPrefs.GetInt("HighScore", 0))
    {
        PlayerPrefs.SetInt("HighScore", score);
        PlayerPrefs.Save();
    }
}

int GetHighScore()
{
    return PlayerPrefs.GetInt("HighScore", 0);
}

PlayerPrefs — синхронны, работают быстро, но не подходят для хранения текстур или сложных массивов. Для сериализации прогресса уровней полезнее будет сохранение в JSON-файл на устройство.

Частые ошибки UI-разработки в Unity

  • Залипание кнопок — часто возникает, если вам не хватает EventSystem на сцене
  • Pixel Perfect элементы — иногда кнопки выглядят мыльно или смещаются — проверьте Canvas Scaler и используйте Sprite PPU = 100
  • Игнорирование мультитача — тап-контролы конфликтуют, если камера обрабатывает одно, а UI — другое
  • Невидимые элементы — проверьте Z-координаты и SortingLayer у Canvas и объектов, особенно в Mixed UI (2D+3D)

Чем раньше обложите интерфейс через систему менеджеров, тем проще будет дальше внедрять новые экраны, улучшать читаемость HUD и добавлять работу с облаком или рекламой.

Оптимизация и тестирование под мобильные устройства

Качественная мобильная игра должна запускаться и плавно работать не только на флагманах. Более 60% Android-устройств, используемых в СНГ и Азии, не имеют мощного GPU, а FPS ниже 30 сразу выражается в плохих оценках и оттоке игроков. Здесь — подходы к оптимизации, профилировке и тестированию, которые позволяют выжать максимум.

Ресурсоёмкие элементы: на что обратить внимание

  • Texture Atlas — объединяйте спрайты в атласы, снижая draw call’ы
  • UI batching — используйте draw order в Canvas для группирования
  • Collider complexity — избегайте составных физических фигур и mesh-коллайдеров на мобилках
  • Animator Overhead — сложные State Machine могут тормозить сцену

Совет: используйте Sprite Packer

Соберите все используемые элементы в Sprite Atlas — стандартный инструмент Unity сделает это автоматически. Включается в Project Settings → Sprite Packer → Always Enabled. Эффект — меньше переключений текстур, стабильнее FPS.

Профилировка производительности

Unity Profiler даёт полную картину по потреблению процессора, памяти и загрузке GPU. Откройте Window → Analysis → Profiler и найдите узкие места. Часто именно UI вызывает больше затрат, чем визуализация объектов.

Что отслеживать:

  • CPU Usage — должно быть не выше 20–30 мс на кадр
  • Garbage Collection spikes — означает повторяющиеся аллокации объектов
  • SetPass Calls — более 100–200 вызовов на сцене говорят о переиспользуемых материалах без батчинга

Общие ориентиры по FPS и производительности

  • Цель FPS: не менее 30 на любом железе, 60 на современных устройствах
  • Размер сборки: желательно < 100 МБ для Android (с .aab форматами даже меньше)
  • Память: менее 150 МБ RAM при простых сценах

Где и как тестировать

  • Android: real device first — эмуляторы не отражают поведение реальных касаний, камеры и реального FPS
  • TestFlight для iOS — отлично подходит для закрытых тестов и SOFT-launch release
  • Firebase Test Lab — облачное тестирование на десятках устройств параллельно

Кейс: на чём чаще всего «падает» игра на Android

  • Отсутствующий AndroidManifest.xml или неверный Bundle ID
  • Неверно указанный Target API — Play Store требует минимальный API 31+
  • Неправильно настроенные Permissions (например, чтение/запись, доступ к сети)
  • Перегрузка UI — на дешёвых устройствах интерфейс лагает, особенно при переходе между сценами

Оптимизация — это процесс с постоянной итерацией. Соберите билд, потестируйте, замерьте профилировку, внесите изменения. И так — пока результат не будет стабильно воспроизводим на ключевых устройствах аудитории.