Artean

Создаем 2D игру на Unity: пошаговое руководство для начинающих

Подготовка среды и инструментария

Первый шаг, с которого мы создаем 2D игру на Unity, — это грамотная настройка среды разработки. Несмотря на дружелюбие Unity к новичкам, важно не теряться в необязательных настройках и сразу изолировать всё, что нужно для комфортной и продуктивной работы.

Как создать 2D игру на Unity с нуля — пошаговое руководство

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

Установка: скачайте Unity Hub. Это централизованная панель управления проектами, версиями и лицензией. Через неё вы можете установить необходимые модули (платформы, редакторы, документацию).

  • Установите Unity Editor с модулем под вашу ОС (Windows или macOS);
  • Добавьте модули сборки, если вы планируете делать WebGL или Android-платформу — это можно сделать позже;
  • Выберите шаблон “2D Core” при создании проекта — он очищенный от 3D-зависимостей и отлично подходит для 2D-механик.

Язык программирования: Unity использует C#. Если вы не знакомы с ним, достаточно базовых знаний: переменные, условия, циклы, методы. Для стартового понимания подойдут:

  • Официальный гайд от Microsoft;
  • Unity Learn — платформа с заданиями и туториалами;
  • Youtube-каналы: Brackeys (архив), GameDev Guide — простые и визуальные;

Интерфейс редактора:

  • Scene — визуальное представление мира игры;
  • Game — результат, который увидит игрок;
  • Hierarchy — список всех объектов на сцене;
  • Project — иерархия всех файлов и assets проекта;
  • Inspector — показывает параметры выбранного объекта или компонента;
  • Console — сообщения от скриптов, предупреждения, ошибки.

Рекомендуется изменить фон IDE на тёмный режим (Editor Theme), чтобы снизить утомляемость глаз. Это доступно в Unity, начиная с бесплатной лицензии Personal.

Организация Assets: заранее создайте папки:

  • Scripts — для всех .cs файлов;
  • Sprites — изображения, визуальные ассеты;
  • Prefabs — повторно используемые объекты;
  • Scenes — уровни игры;
  • UI — всё, что относится к интерфейсу;
  • Audio — при необходимости, звуки и музыка.

Это обеспечит чистоту проекта и сэкономит часы при масштабировании. Хорошая практика — использовать префиксы в названиях файлов (например, UI_ScoreText), чтобы в текстовом поиске быстро находить то, что нужно.

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

Описание концепции и механики будущей игры

Прежде чем писать код или искать изображения героев, нужно чётко ответить себе: во что человек будет играть? Без заранее понятной концепции даже простая mechanics-heavy игра может стать бессвязным набором действий.

Выбор формата: для первой игры критически важно не завышать планку. Идеальны шорт-механики:

  • Endless runner — персонаж бежит вправо, избегая препятствий и собирая очки;
  • Top-down shooter — управление кораблём, уничтожение врагов с видом сверху;
  • Кликер — игрок нажимает, чтобы производить ресурсы, апгрейдить параметры;
  • Платформер — прыжковая механика, тайминговые вызовы и ловушки.

Мини-документация (даже на листе бумаги):

  • Жанр: платформер;
  • Цель игрока: пройти уровень, избежав врагов;
  • Основные действия: движение, прыжок, возможно стрельба;
  • Противники: охранники-патрули, шипы;
  • Условия завершения: добраться до выхода или собрать ключи.

На этом этапе стоит решить: будет ли игра иметь уровни или бесконечный режим; нужна ли прогрессия; требуется ли хранилище результатов. Чем яснее вы это понимаете заранее — тем проще реализовать.

Пример простой игровой механики: игрок управляет персонажем, который бежит по автоматически прокручивающемуся миру (parallax background). Клики мыши/тач — прыжок. Враг — двигающийся GameObject с BoxCollider2D. Столкновение = поражение.

Такой шаблонный проект можно развить до бесконечности: бонусы, смена обстановки, уровни сложности, улучшения. Но на старте важна главная идея: игра должна быть понятна и играбельна в течение 20 секунд после запуска.

Вопрос к себе: назовите игру, в которую вы «залипали» дольше 30 минут, не осознавая времени. Почему это происходило? Попробуйте воссоздать этот крючок в своей механике.

Создание сцены и интерфейса: визуальная основа

Теперь, когда идея игры сформирована, начинаем собирать визуальную сцену. Этот этап наиболее вдохновляющий — за пару часов можно увидеть свои задумки в действии.

Сцена по умолчанию включает: Main Camera и Directional Light (в 2D можно удалить его). Начинаем наполнять её объектами:

  • Создайте пустой объект Environment; в него поместите землю, фон, платформы;
  • Добавьте Sprite в сцену: Right Click → 2D Object → Sprite;
  • Импортируйте изображения в папку Sprites; Unity автоматически распознает .png как спрайт. Выберите Sprite (2D and UI) в настройках texture type.

Важно: соблюдайте одинаковый пиксель-денсити и разрешения. Если фон весит 4 Мб, а герой — 12 Кб и в разных стилях, игра будет выглядеть «поросячьей сборкой». Лучше использовать готовые ассеты из Unity Asset Store:

  • Kenney assets — открытые лицензии, аккуратные стили;
  • Pixel Adventure, SunnyLand, Tiny Heroes — часто используются в туториалах;

Parallax Background: для ощущения глубины добавьте 2–3 слоя фонов с разной скоростью движения. Создайте несколько пустых объектов на разных слоях (настройте их Sorting Layer), прикрепите SpriteRenderer и плавно передвигайте слои скриптом.

Создание игрока:

  1. Добавьте GameObject и примените спрайт героя;
  2. Прикрепите компонент Rigidbody2D для физики;
  3. Добавьте BoxCollider2D (или PolygonCollider2D для сложной формы);
  4. Закрепите тег “Player” для дальнейшей логики interactivity и коллизий.

Интерфейс игры (HUD):

  • Создайте CanvasUI → Text (или TextMeshPro);
  • Разместите счётчик очков, жизней и кнопку restart;
  • Добавьте UI → Button с методом OnClick, привязанным к скрипту рестарта.

Советы UI-организации: используйте Canvas Scaler с параметром Scale with Screen Size, чтобы интерфейс оставался прямопропорционален разрешению экрана. Используйте контейнеры: VerticalLayoutGroup, HorizontalLayoutGroup для автоматического расположения элементов.

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

Управление персонажем и взаимодействие

Живая игра начинается с реакции на действия пользователя. Когда герой двигается, прыгает, стреляет — появляется ощущение контроля. Именно здесь зарождается геймплей. Мы рассмотрим, как добавить скрипты, чтобы персонаж начал реагировать на нажатия клавиш, столкновения и другие игровые события.

Базовое движение персонажа: создайте новый C# скрипт, назовите его PlayerController и прикрепите к игровому объекту персонажа. Внутри скрипта реализуется логика движения:


public class PlayerController : MonoBehaviour
{
    public float moveSpeed = 5f;
    public float jumpForce = 10f;

    private Rigidbody2D rb;
    private bool isGrounded = true;

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

    void Update()
    {
        float xInput = Input.GetAxis("Horizontal");
        rb.velocity = new Vector2(xInput * moveSpeed, rb.velocity.y);

        if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
        {
            rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
            isGrounded = false;
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.contacts[0].normal.y > 0.5)
        {
            isGrounded = true;
        }
    }
}

Пояснение к коду:

  • Input.GetAxis("Horizontal") возвращает -1 до 1 в зависимости от нажатой клавиши (A/D или стрелки);
  • Rigidbody2D управляет физикой; скорость обновляется при каждом кадре;
  • Прыжок выполняется через AddForce() с проверкой — можно прыгнуть только с земли;
  • Коллизия проверяется по нормали — чтобы прыгать только при касании верха (не боковая стена);

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

Анимации и их переключение: если используете анимированного персонажа, не забывайте о Animator Controller. В нём можно создать состояния (idle, run, jump) и переключать их через параметры:


animator.SetBool("isRunning", xInput != 0);
animator.SetBool("isGrounded", isGrounded);

Добавьте компонент Animator к персонажу и свяжите его с заранее подготовленным animator controller.

Физика и Collider’ы: без коллизий персонаж может “провалиться” сквозь землю. Убедитесь, что у вашего пола и платформ есть компонент BoxCollider2D или TilemapCollider2D (если использовали Tilemap). Игровой объект персонажа должен иметь как минимум:

  • Rigidbody2D (Body Type: Dynamic);
  • BoxCollider2D (можно использовать CapsuleCollider2D для улучшенного касания);

Для скользящего или «липкого» поведения на платформах, проверьте настройки:

  • Добавьте слой ground и укажите на нём платформу;
  • В настройках Physics2D включите «Friction» минимальную (0), если персонаж тормозит слишком резко;
  • Используйте PhysicsMaterial2D с настроенными значениями;

Debugging и отладка: часто проблема не в коде, а в порядке выполнения или состава компонента. Используйте:


Debug.Log("Player Jumped!");

Добавляйте это по ключевым точкам логики, чтобы видеть порядок действий. Unity Console покажет сообщение, если условие выполнено.

Как проверить плавность: обратите внимание на отзывчивость управления. Если персонаж «тормозит» или слишком резко меняет анимацию — поработайте с параметрами:

  • moveSpeed и jumpForce — регулируют ощущение физики;
  • Частота FixedUpdate() — влияет на стабильность физики (изменять только с пониманием);
  • Линейная интерполяция Rigidbody — сглаживает перемещения;

Добавляя эти подробности, игрок получает тот самый геймфлоу. Автоматические реакции в момент нажатия создают удовольствие и вовлечённость.

Препятствия, враги и простейшая логика AI

Вовлечённость игрока во многом зависит от вызовов. Угроза поражения, необходимость уклоняться, выбирать момент — всё это требует сценариев поведения объектов, которые не просто стоят — они “живут”.

Начнем с простых врагов-патрульных. Это объекты, у которых есть движение туда-обратно, иногда со сменой спрайта или анимации:


public class EnemyPatrol : MonoBehaviour
{
    public float speed = 2f;
    public Transform pointA;
    public Transform pointB;

    private Vector3 target;

    void Start()
    {
        target = pointB.position;
    }

    void Update()
    {
        transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);

        if (Vector3.Distance(transform.position, target) < 0.1f)
        {
            target = target == pointA.position ? pointB.position : pointA.position;
            Flip();
        }
    }

    void Flip()
    {
        Vector3 scale = transform.localScale;
        scale.x *= -1;
        transform.localScale = scale;
    }
}

Объяснение:

  • Враг перемещается между двумя точками (GameObject с позициями);
  • По достижении цели — инвертирует масштаб по оси X, создавая эффект разворота;

Для AI-преследования (простой зомби-гонщик):


public Transform player;

void Update()
{
    float distance = Vector2.Distance(transform.position, player.position);
    if (distance <= 5f)
    {
        transform.position = Vector2.MoveTowards(transform.position, player.position, speed * Time.deltaTime);
    }
}

Реакция на столкновение: используйте OnCollisionEnter2D(Collision2D collision) или OnTriggerEnter2D(Collider2D other) — второй требует включённого флага «Is Trigger». Создайте HealthSystem:


public int health = 3;

private void OnTriggerEnter2D(Collider2D collision)
{
    if (collision.CompareTag("Enemy"))
    {
        health--;
        if (health <= 0)
        {
            Die();
        }
    }
}

Обратите внимание: у игрового объекта “враг” должен быть назначен тег Enemy, чтобы использовать CompareTag(). Это предпочтительнее, чем проверка по имени объекта — ускоряет исполнение и упрощает код.

Враг с анимацией: используйте Animator Enemy’а, переключайтесь на "Attack" или "Dead" состояние в зависимости от события:


animator.SetTrigger("Attack");

Ловушки: добавьте объекты со спрайтами и BoxCollider2D (Is Trigger = true). При контакте с игроком вызывайте событие потери жизни.

Балансировка: на старте создавайте 1 врага и 1 ловушку. Если игрок умирает дважды за 10 секунд игры — усложнение неуместно. Используйте формулу:

  • 1 вызов в 7–10 секунд — поддерживает тонус мозга и интерес;
  • 3 разных типа опасности на одном уровне даёт разнообразие, но не перегружает;

Плейтест: пригласите 1–2 знакомых пройти уровень. Наблюдайте: где они застряли? Слишком сложно? Или скучно? Дайте им попробовать без подсказок. Это даст больше понимания, чем неделя автотестов.

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

Сохранение прогресса, счётчики и геймплейные циклы

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

Счётчики очков и сбор предметов: добавьте в игру предметы (например, звёзды или монеты). Это обычные GameObject с BoxCollider2D, настроенным как Is Trigger. При столкновении с игроком предмет исчезает, а счёт увеличивается:


int score = 0;

private void OnTriggerEnter2D(Collider2D other)
{
    if (other.CompareTag("Coin"))
    {
        score += 10;
        Destroy(other.gameObject);
        UpdateScoreUI();
    }
}

Не забудьте задать тег Coin вашему объекту. Функция UpdateScoreUI() обновляет текстовое поле TextMeshProUGUI или Text в Canvas:


public Text scoreText;

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

Сохранение данных: PlayerPrefs

Для простого сохранения без базы данных или внешнего файла используйте PlayerPrefs — встроенный механизм хранения значений типа int, float и string. Например, сохранить лучший результат:


PlayerPrefs.SetInt("BestScore", score);

Для загрузки значения при старте игры:


int bestScore = PlayerPrefs.GetInt("BestScore", 0);

Если хотите сбросить все сохранения — используйте PlayerPrefs.DeleteAll() (будьте осторожны, делайте это только при отладке).

Игровой цикл: допустим, игрок проиграл — как запустить игру заново?


using UnityEngine.SceneManagement;

public void RestartGame()
{
    SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}

Реализуйте это через кнопку в Canvas с событием OnClick, привязанным к методу RestartGame(). Это позволит возвращаться в игру после поражения без выхода в меню.

Меню «поражение»: Появление панели при проигрыше реализуем через активацию UI-объекта:


public GameObject gameOverPanel;

public void ShowGameOver()
{
    gameOverPanel.SetActive(true);
}

Добавьте в сцену UI-Panel с надписью “Вы проиграли” и кнопками «Заново» и «Выход». Не забывайте отключить панель при запуске игры: gameOverPanel.SetActive(false);

Мини-цикл: игра-победа-переиграть: если вводите условия победы (например, собраны все монеты или достигнут выход), рекомендуется задать условие перехода на финальный экран:


if (score >= 100)
{
    SceneManager.LoadScene("WinScene");
}

Создайте отдельную сцену WinScene с надписью «Поздравляем!» и вариантом переиграть.

Как понять, «игра работает»? Игровой цикл считается удовлетворительным, если:

  • Игроку не скучно переиграть 3 раза подряд;
  • Он запоминает правила без подсказок после 1 минуты;
  • У него появляется челлендж «взять больше очков» или «пройти без урона»;

Интересный факт: по статистике Steam, менее 42% пользователей доходят до конца начальной миссии даже в популярных играх. Это значит — ваш геймплей должен цеплять не только механикой, но и отзывчивостью, предсказуемостью, простыми метриками прогресса (очки, очки жизни).

Сборка, публикуемая версия и что дальше

Вы разработали рабочий прототип. Что дальше? Показываем игру миру. Для этого она должна быть собрана в исполняемый файл под нужную платформу. Unity делает это просто: достаточно выбрать платформу и сделать экспорт. Но есть нюансы, которые важно не упустить.

Сборка игры: откройте File → Build Settings. Выберите нужную платформу:

  • Windows — стабильный вариант для ПК;
  • WebGL — позволяет размещать игру прямо в браузере;
  • Android — требует установки Android Build Support;

Включите сцену в «Scenes In Build» (нажмите Add Open Scenes). Затем нажмите Build, выберите папку. Unity сгенерирует исполняемую версию игры (.exe или index.html, в зависимости от типа сборки).

Публикация:

  • Itch.io — отлично подходит для прототипов; бесплатный, дружественный к инди-разработчикам. Поддерживает WebGL и загрузку .zip архивов;
  • Google Play Console — идеальный старт для мобильной версии. Но потребует регистрации как разработчик (25 USD единоразово) и грамотной работы с Play Asset Delivery, если приложение требует более 100 Мб;
  • Свой сайт — разместите игру как iframe WebGL-версии или выкладывайте сборку на облако (например, Dropbox) с прямой ссылкой на скачивание;

Что нельзя делать при публикации:

  • Использовать чужую музыку, графику без лицензии — Google и Itch блокируют такие игры;
  • Встраивать API или сервисы аналитики без политики конфиденциальности;
  • Публиковать сборку с сообщениями Debug.Log в релизной версии — это влияет на производительность и лишний вес логов;

Как протестировать игру:

  • Попросите 3–5 человек разного возраста пройти игру и записать, где они теряются;
  • Следите за действиями: если игрок не находит кнопку старт или не понимает, как прыгать — это не его вина, а упущение UX;
  • Составьте Google Form или Notion-таблицу с вопросами: “насколько сложно?”, “хочешь ли сыграть ещё?”, “что не понравилось?”;

Итерации — залог улучшения: первая версия редко бывает идеальной. Отзывы дают направление: кто-то хочет больше уровней, кто-то — другой стиль графики. Главное — не переоценить первое мнение, а собрать пул повторяющихся паттернов.

Что делать после публикации:

  • Добавить уровень сложности;
  • Добавить таймер или модификаторы;
  • Интегрировать внутриигровую валюту (например, для продолжения после проигрыша);
  • Улучшить анимацию или UI (например, анимированный счёт);

Вы довели игру до состояния, когда она живёт независимо и может путешествовать от компьютера к компьютеру. Потратьте время на качественную упаковку — это день, который отдастся высокой оценкой и интересом аудитории.