Unity

Unity — один из самых популярных игровых движков в мире: от инди-пиксель-арта до AAA-проектов. Логика пишется на C# прямо в редакторе, а сборка выполняется для ПК, мобильных и консолей.

Уровень: начальный 19 разделов ⏱ 4–5 часов

1. Что такое Unity

Unity — это движок с редактором сцен и системой компонентов. Ты создаёшь игровые объекты, «вешаешь» на них компоненты (графика, физика, звук) и управляешь поведением через скрипты C#.

ПонятиеОписание
Sceneуровень игры или отдельный экран
Prefabпереиспользуемый «шаблон» объекта
Assetлюбой ресурс: модель, текстура, звук, скрипт
URPсовременный конвейер рендеринга по умолчанию

Лицензия Personal бесплатна до годового дохода в 200 тысяч долларов.

2. Установка и первый проект

Скачай Unity Hub — менеджер версий движка:

  1. Установи Unity Hub и зарегистрируй аккаунт Unity.
  2. Во вкладке Installs добавь Unity 6 (или LTS) с модулями для нужных платформ.
  3. Создай проект по шаблону 3D (URP).
URP даёт красивую физически корректную картинку из коробки. Для учебных простых сцен можно выбрать 3D (Built-in) — разница в настройках материалов.

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

Главные окна Unity:

Горячие клавиши: W/E/R — переместить, повернуть, масштабировать; F — сфокусироваться на объекте.

4. Объекты, компоненты и Transform

Любой объект в сцене — GameObject. Его свойства задают компоненты: Transform (позиция, поворот, масштаб), Mesh Filter + Mesh Renderer (графика), Collider (столкновения).

Добавь куб:

  1. Hierarchy → ПКМ → 3D Object → Cube.
  2. Выбери куб — в Inspector появится компонент Transform.
  3. Измени Position, Rotation, Scale — объект сдвинется в Scene.
GameObject.CreatePrimitive(PrimitiveType.Cube);
new GameObject("Имя");

Векторы работают через Vector3: transform.position += Vector3.up * 2f;

5. Сцены и сохранение

Сцена объединяет объекты уровня. Сохраняемая единица — .unity файл в папке Assets.

// Создать новую сцену в коде
SceneManager.CreateScene("Level2");
SceneManager.LoadScene("Level1");

Переключение сцен настраивается в Build Settings → Scenes in Build.

Помни: изменения в режиме Play (кнопка ▶) не сохраняются сами по себе. Редактируй объекты в Scene-режиме и нажимай Ctrl+S.

6. Скрипты на C#

Создай скрипт: Project → ПКМ → Create → C# Script. Двойной клик откроет редактор кода (по умолчанию Visual Studio/Rider).

Базовый шаблон движения:

using UnityEngine;

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

    void Update()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        transform.Translate(x * speed * Time.deltaTime, 0, z * speed * Time.deltaTime);
    }
}

Отладка через консоль:

Debug.Log("Привет из Unity");
Debug.LogWarning("Внимание!");
Debug.LogError("Ошибка");

7. Физика: Rigidbody и Collider

Компонент Rigidbody подключает объект к физическому движку: гравитация, толчки, столкновения. Collider задаёт форму для коллизий.

using UnityEngine;

public class Ball : MonoBehaviour
{
    private Rigidbody rb;

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

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            rb.AddForce(Vector3.up * 8f, ForceMode.Impulse);
        }
    }

    void OnCollisionEnter(Collision col)
    {
        Debug.Log("Столкновение с " + col.gameObject.name);
    }
}
OnTriggerEnter срабатывает, когда у коллайдера включён Is Trigger (сигнал без твёрдой стенки) — удобно для зон и предметов.

8. Камера и освещение

Камерой определяется то, что видит игрок. Основные типы освещения — Directional (солнце), Point, Spot.

Сделай камеру «следящей»:

using UnityEngine;

public class FollowCam : MonoBehaviour
{
    public Transform target;
    public Vector3 offset = new Vector3(0, 3, -6);

    void LateUpdate()
    {
        if (target != null)
        {
            transform.position = target.position + offset;
            transform.LookAt(target);
        }
    }
}

С помощью Light.intensity и цвета настраивается атмосфера сцены.

9. Префабы

Префаб — «заводской шаблон» объекта: экземпляры можно плодить в любой сцене, а правки префаба применятся сразу ко всем.

  1. Создай объект, добавь скрипты и компоненты.
  2. Перетащи его из Hierarchy в Project → получится префаб (синий куб в Project).

Создание экземпляра в коде:

public GameObject enemyPrefab;
public Transform spawnPoint;

void Start()
{
    Instantiate(enemyPrefab, spawnPoint.position, spawnPoint.rotation);
}

10. UI: Canvas и кнопки

Интерфейс живёт внутри Canvas. Создай кнопку: Hierarchy → ПКМ → UI → Button (Unity сама создаст Canvas и EventSystem).

Подключи обработчик:

  1. Скрипт public void RestartGame() в классе.
  2. В Inspector кнопки: поле OnClick → знак «+» → перетащи объект со скриптом → выбери метод.
using UnityEngine;
using UnityEngine.UI;

public class HUD : MonoBehaviour
{
    public Text scoreText;
    public void RestartGame() { }

Текст меняется через scoreText.text = value.ToString();

11. Анимация: Animator

Анимации управляются через Animator Controller — граф состояний и переходов.

  1. Импортируй модель с анимациями (FBX) или создай Animation Clip.
  2. Создай Animator Controller в Project, добавь состояния Idle и Run.
  3. Переходы управляются параметрами (bool, float, int).
public Animator anim;

void Update()
{
    anim.SetFloat("Speed", 1f);        // параметр float
    anim.SetBool("IsJumping", true);   // параметр bool
    anim.Play("Run");                  // прямое воспроизведение
}
Параметр в Animator Controller и имя в коде должны совпадать точно — иначе переход не сработает из-за отсутствия параметра.

12. Материалы и сборка игры

Материал определяет, как выглядит поверхность. В URP используй шейдер Universal Render Pipeline/Lit: задаются Base Map, Normal Map, Smoothness, Metallic.

Смена материала в коде:

public Material redMat;

void Start()
{
    GetComponent<Renderer>().material = redMat;
}

Сборка игры:

  1. File → Build Settings — добавь сцены и выбери платформу.
  2. Player Settings — название, иконка, текстуры.
  3. Build — получишь папку с игрой и исполняемым файлом.
Версии проекта храни в системе контроля версий: GitLab с Git LFS для больших ассетов — стандарт для команд Unity.

13. Звук: AudioSource и AudioListener

Звук добавляется двумя компонентами: AudioListener («уши», обычно на камере) и AudioSource («источник»). В ролике (Audio Clip) подкладывается сам файл.

using UnityEngine;

public class CoinSound : MonoBehaviour
{
    public AudioClip clip;

    void OnTriggerEnter(Collider other)
    {
        AudioSource.PlayClipAtPoint(clip, transform.position);
    }
}
ПроизводительностьРекомендация
Формат файлаOGG для музыки, WAV для коротких эффектов
Фильтрыне вешайте Reverb на каждый источник
Количестводесять-двадцать одновременно — комфортный максимум
Воспроизведение на стерео-колонках и телефоне звучит по-разному. Слушайте микс в обоих вариантах, а не только в редакторе.
Фоновую музыку останавливайте при паузе игры: Time.timeScale = 0 не останавливает AudioSource сам по себе.

14. Сохранение и загрузка: база

Сохранить игровой прогресс можно двумя способами: PlayerPrefs для простых значений и файлы JSON для структур. Начнём с простого хранилища.

using System;
using UnityEngine;

[Serializable]
public class SaveData
{
    public int score;
    public string level = "Level1";
}

public static class SaveSystem
{
    public static void Save(SaveData data)
    {
        string json = JsonUtility.ToJson(data);
        PlayerPrefs.SetString("save", json);
        PlayerPrefs.Save();
    }
}
Сделайте автоматическое сохранение при паузе и выходе — пользователи потеряют меньше прогресса и реже покидают игру.
JSON от JsonUtility не любит словари и сложные вложенности — для больших данных используйте Newtonsoft JSON или базу данных.
JsonUtility подходит для академических целей, а продакшн-сохранения переводите на Newtonsoft JSON или локальную БД — это упростит версионирование сохранений при обновлениях игры.

15. Оптимизация проекта

Заторможенная игра разочаровывает сильнее любого бага. Настройка фокуса: сначала профилирование, потом правки.

// Простой счётчик кадров
float fps;

void Update()
{
    fps = 1f / Time.unscaledDeltaTime;
    Debug.Log($"FPS: {fps:0}");
}
  1. Profiler (Window → Analysis → Profiler) покажет, что тормозит: CPU, GPU или память.
  2. Draw Calls: меньше уникальных материалов, используйте атласы и статичный батчинг.
  3. Свет: запекайте статичное освещение (Baked), движущиеся тени — точечно.
  4. Объекты: отключайте те, что за камерой — пул врагов вместо создания новых.

Для мобильных целей есть отдельный профиль: включите Development Build и подключите Device Profiler. На телефоне картина часто противоположна редактору, поэтому финальные правки делаются по устройству.

Оптимизируйте на целевом устройстве: фрейм-рейт на компьютере ничего не говорит о телефоне. Тестируйте там, где будет игра.
Не оптимизируйте «на глаз» — профилируйте сначала. Любая правка без замера это догадка, а догадки в оптимизации стоят недель.

16. Ввод и управление: Input System

Современный «Input System» пришёл на смену старому Input.GetAxis: управление описывается декларативно и поддерживает клавиатуру, геймпад и тач из одного набора Actions.

using UnityEngine.InputSystem;

public class PlayerMove : MonoBehaviour
{
    [SerializeField] private InputActionReference moveAction;
    [SerializeField] private float speed = 5f;

    void Update()
    {
        Vector2 input = moveAction.action.ReadValue<Vector2>();
        transform.position += new Vector3(input.x, 0, input.y) * speed * Time.deltaTime;
    }
}
Не смешивайте старый и новый ввод в одном проекте: конфликт курсора и дублирование действий приносят мистические баги.
Держите input-ассет отдельно от логики: ребайдинг клавиш делается без пересборки игры.

17. Корутины, async и пул объектов

Игровой цикл диктует свои способы асинхронности: корутины простаивают между кадрами, async/await получает результат из внешнего мира, а пул объектов убирает дорогое создание игровых объектов.

IEnumerator SpawnWave()
{
    for (int i = 0; i < 10; i++)
    {
        SpawnEnemyFromPool();
        yield return new WaitForSeconds(0.5f);
    }
}

void Start() { StartCoroutine(SpawnWave()); }
Каждая Instantiate/Destroy в цикле дёргает GC и физику — на тысяче объектов это заметный «фриз».
Для долгих игровых таймеров корутина — не лучший выбор: считайте время в Update и сравнивайте с накопленным, а корутины оставляйте коротким сценариям.

18. Основы мультиплеера: Netcode для GameObjects

Сетевой код удваивает сложность: состояние объектов — на сервере, а клиенты лишь предсказывают и синхронизируют. Официальное решение для старта — Netcode for GameObjects.

using Unity.Netcode;
using UnityEngine;

public class PlayerState : NetworkBehaviour
{
    public NetworkVariable<int> Score = new(0);

    [Rpc(SendTo.Server)]
    public void TryPickupRpc()
    {
        Score.Value += 10;
    }
}
Никогда не доверяйте клиентскому расчёту очков и здоровья: считайте на сервере, а клиенты лишь запрашивают действия через RPC.
Начните с «двух игроков в комнате»: соединение, спавн, синхронизация позиции — фундамент, на котором позже вырастет всё остальное.

19. Навигация и ИИ: NavMesh

Враги и NPC, которые «разумно» обходят препятствия, в Unity решаются навигационной сеткой: NavMesh генерируется из геометрии уровня, а агенты ходят по ней.

using UnityEngine.AI;

public class EnemyAI : MonoBehaviour
{
    private NavMeshAgent agent;
    [SerializeField] private Transform target;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
    }

    void Update()
    {
        agent.destination = target.position;
    }
}
NavMesh печётся из геометрии: после передвижения стен перегенерируйте сетку в окне Navigation, иначе агенты «пройдут сквозь» новое препятствие.
Добавьте агентам близкие, но разные скорости: движение перестаёт выглядеть синхронно-роботизированным.

20. ScriptableObject: данные отдельно от кода

ScriptableObject — контейнер данных, который живёт в проекте как ассет. Этим он сильнее полей в MonoBehaviour: конфигурация редактируется в Inspector отдельно от сцены и переиспользуется без копий.

// WeaponData.cs
[CreateAssetMenu(fileName = "Weapon", menuName = "Data/Weapon")]
public class WeaponData : ScriptableObject {
    public string displayName;
    public float damage;
    public float fireRate;
}

Архитектурный нюанс: храните в ScriptableObject только данные и «фабрики» конфигов, а логику — в отдельных классах, получающих их в RuntimeInitializeOnLoadMethod или через инъекцию.

Начните с одного системного конфига (например, GameConfig): сразу почувствуете разницу с «полями в каждом объекте».
Не держите в ScriptableObject ссылки на сцены-специфику: ассет «разделяет» её со всеми потребителями.
Совет: ScriptableObject спаривается с паттерном «GameEvent + Listener» — связь между системами становится конфигурацией, а не кодом.

21. Unity Test Framework: EditMode и PlayMode

Игру тестировать сложно, но возможно: Unity Test Framework (UTF) запускает юнит-тесты в двух режимах — EditMode (быстрый, без симуляции времени) и PlayMode (полная сцена, как в редакторе).

// EditMode-тест: логика без сцены
using NUnit.Framework;

public class DamageTests {
    [Test]
    public void DamageReducesHealth() {
        var hp = new Health(100);
        hp.TakeDamage(30);
        Assert.AreEqual(70, hp.Current);
    }
}

Ставка на «чистые» системы (без MonoBehaviour-зависимостей) окупается: их можно покрывать в EditMode без симуляции и получить мгновенные результаты.

Покрывайте сначала экономику (баланс, магазин) и правила игрока — там ошибки дороже всего.
PlayMode-тесты медленные и хрупкие: не гоняйте их в каждой команде, выделяйте «смоук-набор» на каждый пуша.
Держите тесты независимыми от текущей сцены и времени суток: фиксируйте состояние явно, иначе набор «зелёный у тебя, красный у коллеги».

22. Addressables: управление контентом

Большой проект содержит сотни сцен и ассетов; грузить всё сразу — перебор. Addressables — система ссылок на «адресуемые» ассеты, которые загружаются в момент нужды и выгружаются, когда больше не нужны.

using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class Loader {
    AsyncOperationHandle<GameObject> op =
        Addressables.LoadAssetAsync<GameObject>("enemies/Ork");
    op.Completed += h => {
        Instantiate(h.Result);
        Addressables.Release(h);
    };
}

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

Начните с адресов для «тяжёлых» сцен и общих данных: музыка, уровни, префабы редких объектов.
Строго следите за Release: забытый LoadAssetAsync без Release накапливает память, и баг виден только на длинных сессиях.
Для версионирования контента Addressables дружат с CI: билд каталога и бандлов — отдельный шаг пайплайна.

23. Монетизация, реклама и аналитика

Игра — продукт: после релиза нужно платить за сервер, покупать ассеты и, в идеале, зарабатывать. Три столпа — монетизация (встроенные покупки), реклама и аналитика событий.

СпособКогда работает
Разовая покупкаклассическая игра с фиксированной ценой
IAP (встроенные покупки)валюты, предметы, подписки
Реклама (AdMob/Unity Ads)бесплатные игры, «за вознаграждение»

Правило порядка: сначала геймплей и ретеншн, потом монетизация. Реклама «в лицо» на старте убивает игру быстрее, чем её отсутствие.

Валидируйте покупки на сервере (Google Play Billing Library) — клиентская проверка легко обходится.
Перед интеграцией SDK сверяйте политики магазинов: «платный доступ через рекламу» и «детский контент» — разные миры.
Рекламные интеграции делаются через эмиттер «вознаграждённых» показов — дайте игроку выбор, а не насилие.

Что дальше

С языком C# ты уже познакомился в Unity. Для глубокого синтаксиса пройди базу языка Python (логика схожа), а для ГГ моделей и ассетов — Blender и Substance 3D Painter.

← Вернуться к курсам