Создание 3D RPG на Unity с нуля

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

1. Основы Unity и создание мира: ландшафт, освещение и базовое движение персонажа

Основы Unity и создание мира: ландшафт, освещение и базовое движение персонажа

Добро пожаловать на курс «Создание 3D RPG на Unity с нуля». Я рад приветствовать вас в начале этого увлекательного пути. RPG (Role-Playing Game) — это один из самых сложных, но и самых интересных жанров в разработке игр. Мы будем строить наш мир шаг за шагом, начиная с фундамента.

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

Знакомство с Unity: Инструментарий творца

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

После установки Unity Hub и создания нового 3D-проекта, перед вами откроется интерфейс редактора. Он может показаться пугающим, но давайте разделим его на понятные зоны.

!Схема основных окон редактора Unity для быстрой ориентации.

Основные окна:

  • Hierarchy (Иерархия): Это список всех объектов, которые находятся в данный момент на уровне (сцене). Если объекта нет в иерархии, его нет в игре.
  • Scene (Сцена): Ваше рабочее пространство. Здесь вы визуально расставляете объекты, двигаете камеру и строите уровень.
  • Game (Игра): То, что видит игрок через камеру. Это окно предварительного просмотра.
  • Inspector (Инспектор): Самое важное окно для настройки. Когда вы выделяете объект в иерархии, здесь появляются все его свойства (компоненты): координаты, цвет, физика и скрипты.
  • Project (Проект): Это ваш жесткий диск. Здесь лежат все файлы: модели, текстуры, звуки и скрипты.
  • Создание ландшафта (Terrain)

    Любая RPG начинается с мира. В Unity для создания больших открытых пространств используется инструмент Terrain.

    Чтобы создать землю:

  • Нажмите правой кнопкой мыши в окне Hierarchy.
  • Выберите 3D Object -> Terrain.
  • Теперь у вас есть огромная плоская поверхность. Но мир RPG не бывает плоским. Нам нужны горы, долины и реки. В Инспекторе объекта Terrain есть инструменты кисти (Paint Terrain).

    Скульптинг мира

    Выбрав инструмент «Raise or Lower Terrain» (Поднять или опустить ландшафт), вы можете рисовать горы прямо на сцене. Это похоже на лепку из цифровой глины.

    > Хороший левел-дизайн начинается не с деталей, а с крупных форм. Сначала наметьте горы, ограничивающие карту, затем холмы, и только потом — мелкие неровности.

    С точки зрения математики, ландшафт в компьютерной графике часто представляется как карта высот (Heightmap). Это двумерный массив данных, где каждая точка имеет координату высоты.

    Если представить наш ландшафт как функцию , то высота в любой точке зависит от координат и на плоскости.

    Где — функция высоты ландшафта, и — горизонтальные координаты точки на карте, а — итоговая высота этой точки в 3D пространстве.

    Освещение: Создаем атмосферу

    Без света наш мир будет черным. В Unity по умолчанию создается объект Directional Light. Это наше солнце.

    Типы источников света, которые нам пригодятся в будущем: * Directional Light: Имитирует солнце. Лучи параллельны и освещают всю сцену равномерно, независимо от положения источника. * Point Light: Лампочка или костер. Светит во все стороны из одной точки. * Spot Light: Фонарик или прожектор. Светит конусом.

    Для начала нам достаточно настроить Directional Light. Выберите его в иерархии и в Инспекторе измените Rotation (Вращение). Вы увидите, как меняется время суток: тени удлиняются, небо меняет цвет (благодаря процедурному скайбоксу Unity).

    Создание персонажа: Физика и Геометрия

    Пока у нас нет красивой 3D-модели рыцаря или мага, мы будем использовать «прототип» — капсулу. Это стандартная практика в индустрии, называемая «грейбоксинг» (greyboxing).

  • Создайте капсулу: Hierarchy -> Right Click -> 3D Object -> Capsule.
  • Назовите её Player.
  • Поднимите её над землей (инструмент Move Tool или клавиша W), чтобы она не застряла в текстурах.
  • Компонент Rigidbody

    Чтобы наш персонаж подчинялся законам физики (падал вниз, сталкивался со стенами), нам нужно добавить компонент Rigidbody.

  • Выберите Player.
  • В Инспекторе нажмите Add Component.
  • Найдите и выберите Rigidbody.
  • В настройках Rigidbody найдите раздел Constraints и поставьте галочки на Freeze Rotation X и Freeze Rotation Z. Это нужно, чтобы наша капсула не падала и не катилась как бочка, а всегда оставалась вертикальной.
  • Теперь, если вы нажмете кнопку Play (сверху по центру), капсула упадет на землю под действием гравитации.

    Программирование движения

    Чтобы капсула двигалась по нашей воле, нам нужен скрипт. В Unity используется язык C#.

  • В окне Project нажмите правой кнопкой мыши -> Create -> C# Script.
  • Назовите его PlayerController (без пробелов!).
  • Перетащите этот скрипт на объект Player.
  • Дважды кликните по скрипту, чтобы открыть его.
  • Код движения

    Напишем простой код для перемещения. Удалите всё содержимое и вставьте следующее:

    Разбор логики и математики движения

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

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

    Формула обновления позиции выглядит так:

    Где: * — новая позиция объекта (вектор ). * — текущая позиция объекта. * — вектор направления движения (полученный от нажатия клавиш, например при движении вправо). * — скорость движения (наша переменная speed). * — время, прошедшее с последнего кадра (Time.deltaTime).

    !Иллюстрация того, как вычисляется новая позиция персонажа в каждом кадре.

    Почему важно умножать на Time.deltaTime? Компьютеры работают с разной скоростью. У одного игрока игра выдает 60 кадров в секунду (FPS), у другого — 30. Метод Update() вызывается каждый кадр. Если мы будем просто прибавлять скорость, то игрок с 60 FPS будет бегать в два раза быстрее игрока с 30 FPS. Умножение на время, прошедшее между кадрами (), делает скорость движения независимой от частоты кадров. Если кадров много, маленький. Если кадров мало, большой. В итоге пройденное расстояние за секунду будет одинаковым.

    Заключение

    Поздравляю! Вы сделали первый шаг к созданию своей RPG. У вас есть мир (Terrain), есть солнце (Directional Light) и есть герой (Capsule), который умеет бегать по этому миру, подчиняясь законам физики.

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

    2. Анимация и характеристики: настройка контроллера, здоровье, мана и система прокачки

    Анимация и характеристики: настройка контроллера, здоровье, мана и система прокачки

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

    Сегодня мы вдохнем жизнь в нашего персонажа. Мы заменим капсулу на 3D-модель, настроим анимации через Animator Controller и напишем скрипт характеристик (Stats), который станет сердцем ролевой системы.

    Оживление героя: Animator Controller

    В Unity за воспроизведение анимаций отвечает компонент Animator. Но просто «проиграть анимацию» недостаточно. Нам нужна логика: когда стоять, когда бежать, а когда атаковать. Для этого используется State Machine (Конечный автомат).

    Понимание State Machine

    Представьте мозг персонажа как набор состояний. В один момент времени он может находиться только в одном состоянии (например, «Бег»). Чтобы перейти в состояние «Прыжок», должно произойти определенное событие (нажатие пробела).

    !Схематичное изображение логики переключения анимаций.

    Blend Trees (Деревья смешивания)

    В современных играх редко используют резкое переключение между «Стоять» и «Бежать». Обычно персонаж сначала идет медленно, потом ускоряется. Для этого в Unity существуют Blend Trees.

    Blend Tree позволяет смешивать несколько анимаций на основе одного числового параметра (например, скорости). Если скорость 0 — играет анимация Idle. Если 0.5 — смесь Idle и Walk. Если 1.0 — чистый Run.

    Настройка аниматора

    Предположим, у вас есть модель персонажа с набором анимаций (их можно взять на сайте Mixamo или в Unity Asset Store). Вот алгоритм действий:

  • Создание контроллера: В окне Project нажмите правой кнопкой мыши -> Create -> Animator Controller. Назовите его PlayerAnimator.
  • Применение: Выберите модель вашего персонажа в иерархии и перетащите этот контроллер в слот Controller компонента Animator.
  • Параметры: Откройте окно Animator. Вкладка Parameters -> + -> Float. Назовите параметр Speed.
  • Создание Blend Tree: Правой кнопкой в сетке окна Animator -> Create State -> From New Blend Tree. Дважды кликните по нему.
  • Настройка: В инспекторе Blend Tree добавьте три поля (Motion). Назначьте им анимации: Idle, Walk, Run. Unity автоматически расставит пороги (Thresholds) значений, например, 0, 0.5 и 1.
  • Теперь, меняя параметр Speed, мы будем плавно переключать анимации.

    Связь кода и анимации

    Наш скрипт PlayerController из прошлого урока двигал капсулу, но не знал об анимациях. Давайте это исправим.

    Нам нужно передавать текущую скорость персонажа в Animator каждый кадр.

    Теперь, когда вы нажимаете клавиши, speedPercent становится больше нуля, и Animator плавно переводит персонажа из покоя в бег.

    Характеристики персонажа (Stats System)

    RPG невозможна без цифр. Здоровье (HP), Мана (MP), Опыт (XP) и Уровень (Level) — это базис.

    Создайте новый скрипт CharacterStats.cs. Этот скрипт будет хранить данные, но не будет отвечать за движение. Это принцип разделения ответственности.

    Математика уровня и опыта

    Как определить, сколько опыта нужно для следующего уровня? Линейный рост (каждый уровень требует 1000 XP) скучен. Игроку должно быть сложнее достигать высоких уровней. Обычно используется экспоненциальная зависимость.

    Формула расчета необходимого опыта для следующего уровня может выглядеть так:

    Где: * — количество опыта, необходимое для получения следующего уровня. * — базовое значение опыта для первого уровня (например, 100). * — множитель сложности (например, 1.1 или 1.2). * — текущий уровень персонажа.

    Если и , то: * Для 1 уровня нужно: XP. * Для 2 уровня нужно: XP. * Для 10 уровня нужно: XP.

    Реализация в коде

    Вот пример базовой структуры класса характеристик:

    Разбор ключевых моментов

  • Mathf.Clamp: В методе TakeDamage мы используем эту функцию. Она не позволяет переменной выйти за заданные границы. Здоровье не может быть меньше 0 и больше maxHealth.
  • Mathf.Pow: Это функция возведения в степень, которую мы используем для расчета кривой опыта.
  • Перенос опыта: При повышении уровня мы вычитаем expToNextLevel из currentExp, а не обнуляем его. Если игрок получил 150 XP, а нужно было 100, то на следующий уровень перейдет 50 XP.
  • !График экспоненциального роста требований к опыту.

    Интеграция систем

    Теперь у нас есть два независимых скрипта: PlayerController (движение) и CharacterStats (данные). В будущем мы свяжем их еще теснее. Например, когда currentHealth станет равным 0, CharacterStats вызовет метод Die(), который должен сообщить PlayerController, что нужно отключить управление, и сообщить Animator, что нужно проиграть анимацию смерти.

    > Хорошая архитектура кода в Unity строится на компонентах, которые знают друг о друге ровно столько, сколько необходимо для работы, и не более.

    Заключение

    Сегодня мы превратили бездушную капсулу в заготовку для героя. У него есть тело (модель), нервная система (Animator Controller) и паспортные данные (CharacterStats).

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

    3. Боевая система и ИИ: программирование врагов, логика атак и получение урона

    Боевая система и ИИ: программирование врагов, логика атак и получение урона

    В предыдущих статьях мы создали мир, научили персонажа двигаться и наделили его характеристиками (здоровьем и маной). Но RPG — это не симулятор ходьбы. Это жанр, где герой преодолевает препятствия, часто с мечом или магией в руках.

    Сегодня мы превратим наш проект в игру. Мы создадим врагов, наделим их искусственным интеллектом (ИИ) для преследования игрока и реализуем систему нанесения урона.

    Основа навигации: NavMesh

    Прежде чем враг сможет атаковать, он должен уметь дойти до игрока, обходя деревья, камни и стены. Писать алгоритмы поиска пути с нуля (например, A*) — задача сложная и не всегда нужная. В Unity для этого есть встроенный инструмент — Navigation Mesh (или NavMesh).

    NavMesh — это упрощенная геометрия уровня, которая говорит ИИ: «Здесь можно ходить, а здесь стена». Это невидимая сетка, накладываемая поверх вашего ландшафта.

    Настройка NavMesh

  • Откройте окно навигации: Window -> AI -> Navigation.
  • Выберите объекты, по которым можно ходить (ваш Terrain и плоские платформы).
  • В окне Navigation перейдите во вкладку Object и поставьте галочку Navigation Static. Это скажет движку, что этот объект неподвижен и является частью пола.
  • Перейдите во вкладку Bake и нажмите кнопку Bake.
  • После этого вы увидите, как на земле появится синяя сетка. Это и есть зона, доступная для перемещения врагов.

    !Синяя зона показывает доступные пути для ИИ, исключая препятствия.

    Создание врага

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

  • Создайте цилиндр: GameObject -> 3D Object -> Cylinder. Назовите его Enemy.
  • Добавьте компонент NavMeshAgent. Этот компонент отвечает за перемещение объекта по синей сетке, которую мы только что запекли.
  • Логика ИИ: Конечный автомат (FSM)

    Поведение простых мобов в играх часто строится на Finite State Machine (Конечный автомат). У врага есть состояния, и он переключается между ними в зависимости от условий.

    Типичные состояния: * Idle (Покой): Игрок далеко, враг стоит или патрулирует. * Chase (Преследование): Игрок вошел в зону видимости, враг бежит к нему. * Attack (Атака): Враг догнал игрока и наносит урон.

    Чтобы определить, в каком состоянии находиться, нам нужно знать расстояние между врагом и игроком. Здесь нам поможет математика.

    Математика дистанции

    Расстояние между двумя точками в трехмерном пространстве вычисляется по формуле Евклидова расстояния:

    Где: * — итоговое расстояние между объектами. * — координаты позиции врага. * — координаты позиции игрока.

    В Unity нам не нужно писать эту формулу вручную, так как есть оптимизированный метод Vector3.Distance(a, b).

    Программирование врага

    Создайте скрипт EnemyController.cs и добавьте его на объект Enemy. Нам также понадобится ссылка на игрока, чтобы знать, за кем бежать.

    Не забудьте присвоить вашему объекту игрока тег Player в инспекторе, иначе GameObject.FindGameObjectWithTag не сработает.

    Архитектура урона: Интерфейсы

    Теперь самое интересное. Как нанести урон? Можно написать метод TakeDamage в скрипте игрока. И такой же метод в скрипте врага. И такой же в скрипте разрушаемого ящика.

    Но что, если мы хотим ударить мечом, не задумываясь, кто перед нами? Здесь на помощь приходят Интерфейсы.

    Интерфейс — это контракт. Если скрипт подписывает этот контракт, он обязан иметь определенные методы.

    Создайте скрипт IDamageable.cs (заметьте, это не MonoBehaviour):

    Теперь вернемся к нашему скрипту CharacterStats из прошлого урока и заставим его выполнять этот контракт.

    Теперь и игрок, и враг (если мы добавим ему CharacterStats) могут получать урон одинаковым способом.

    Реализация атаки игрока

    Чтобы игрок мог атаковать, нам нужно определить, на кого он навел курсор (или кто находится перед ним). В классических RPG часто используется управление мышью.

    Мы будем использовать Raycast (Луч). Это невидимый лазер, который стреляет из камеры в точку, куда указывает мышь, и сообщает, во что он попал.

    Создайте скрипт PlayerCombat:

    Математика кулдауна (Перезарядки)

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

    Логика проста: мы не можем атаковать, пока текущее время меньше времени следующей возможной атаки. Или, как в нашем примере, мы вычитаем время из таймера.

    Формула проверки возможности атаки:

    Где: * — текущее время в игре. * — время, когда была совершена последняя атака. * — фиксированное время перезарядки (пауза между ударами).

    В коде мы реализовали это через обратный отсчет (attackTimer -= Time.deltaTime), что математически эквивалентно.

    !Луч Raycast проходит сквозь экран в 3D мир и определяет объект под курсором.

    Интеграция анимаций

    Чтобы бой выглядел красиво, в момент вызова Attack() в скрипте PlayerCombat нужно обращаться к аниматору:

    А в скрипте EnemyController, внутри метода AttackTarget(), нужно запускать анимацию атаки врага. Важно помнить, что урон должен наноситься не мгновенно, а в момент удара визуальной модели. Для этого в Unity используются Animation Events (События анимации), которые позволяют вызвать функцию в конкретном кадре анимации, но это тема для отдельного глубокого разговора.

    Заключение

    Сегодня мы заложили фундамент боевой системы. У нас есть:

  • NavMesh, позволяющий врагам ориентироваться в пространстве.
  • ИИ, который умеет преследовать игрока и останавливаться для атаки.
  • Интерфейс IDamageable, унифицирующий получение урона.
  • Raycast, позволяющий игроку выбирать цели и атаковать их.
  • Теперь ваш проект уже напоминает игру. В следующей статье мы займемся созданием пользовательского интерфейса (UI), чтобы игрок видел свои полоски здоровья, и добавим систему инвентаря, чтобы подбирать предметы с поверженных врагов.

    4. RPG-системы: разработка инвентаря, экипировки, диалогов с NPC и журнала квестов

    RPG-системы: разработка инвентаря, экипировки, диалогов с NPC и журнала квестов

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

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

    Архитектура данных: ScriptableObjects

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

    В Unity для хранения данных идеально подходят ScriptableObjects. Это контейнеры данных, которые существуют независимо от объектов на сцене. Они живут в файлах проекта.

    Создание шаблона предмета

    Создайте скрипт ItemData.cs. Обратите внимание, он наследуется не от MonoBehaviour, а от ScriptableObject.

    Теперь, нажав правой кнопкой мыши в окне Project, вы можете выбрать Create -> Inventory -> Item и создать файл, например, «Sword». В инспекторе вы сможете настроить его имя, иконку и характеристики. Это наш «паспорт» предмета.

    !Схема показывает связь между файлом ScriptableObject на диске и ссылкой на него в скрипте инвентаря

    Система Инвентаря

    Инвентарь состоит из двух частей: Логика (список предметов в коде) и Визуализация (отображение иконок на экране).

    Логическая часть

    Создадим класс Inventory, который будет хранить список наших ItemData. Мы сделаем его синглтоном (Singleton), чтобы к инвентарю можно было легко обратиться из любого места игры.

    Визуализация (UI)

    Для отображения предметов нам понадобится Canvas. В Unity UI строится на системе якорей и панелей.

  • Создайте Canvas.
  • Внутри создайте Panel и назовите её InventoryPanel.
  • На панель добавьте компонент Grid Layout Group. Он автоматически расставит дочерние элементы в сетку.
  • Математически позиция каждого слота в сетке рассчитывается движком, но полезно понимать принцип. Если у нас есть индекс предмета , ширина ячейки и количество колонок , то координаты центра ячейки можно выразить так:

    Где: * — горизонтальная координата ячейки. * — вертикальная координата ячейки (обычно отрицательная, так как отсчет идет сверху вниз). * — порядковый номер предмета в списке (начиная с 0). * — количество колонок в сетке инвентаря. * — ширина ячейки (включая отступы). * — высота ячейки (включая отступы). * — операция взятия остатка от деления на . * — операция округления вниз до целого числа.

    Вам нужно создать скрипт InventoryUI, который подпишется на событие onItemChangedCallback. Когда событие срабатывает, скрипт должен очистить текущие иконки в InventoryPanel и создать новые на основе списка items.

    Экипировка и изменение характеристик

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

    Формула расчета итогового урона или защиты будет суммой базового значения и всех модификаторов:

    Где: * — итоговое значение характеристики (например, урон). * — базовое значение характеристики персонажа (без одежды). * — количество надетых предметов. * — бонус к характеристике от -го предмета экипировки.

    В коде это реализуется через добавление списка экипировки в CharacterStats или создание отдельного EquipmentManager, который при надевании предмета вызывает метод AddModifier у характеристик.

    Система взаимодействия (Interaction)

    Чтобы поднять предмет или поговорить с NPC, нам нужен универсальный способ взаимодействия. Мы уже использовали интерфейс IDamageable для боя. Теперь создадим интерфейс IInteractable.

    Любой объект (сундук, NPC, лежащий меч), с которым можно взаимодействовать, будет иметь скрипт, реализующий этот интерфейс.

    В скрипте игрока мы будем пускать луч (Raycast) или проверять сферу вокруг (OverlapSphere). Если находим объект с IInteractable, и игрок нажимает клавишу «E», вызываем метод Interact().

    Диалоговая система

    Диалоги — это основа сюжета. Простая система диалогов состоит из двух элементов: Данные и Менеджер.

    Данные диалога

    Создайте обычный класс (не наследуемый от MonoBehaviour), чтобы хранить реплики.

    Атрибут [System.Serializable] позволяет отображать этот класс внутри Инспектора Unity.

    Менеджер диалогов

    Скрипт DialogueManager будет отвечать за открытие диалогового окна, вывод текста буква за буквой (эффект печатной машинки) и закрытие окна.

    Для хранения предложений удобно использовать структуру данных Очередь (Queue). Это принцип FIFO (First In, First Out — первый вошел, первый вышел).

    !Иллюстрация трубы, куда с одной стороны входят данные, а с другой выходят в том же порядке

    Журнал квестов

    Квесты тесно связаны с диалогами. Обычно в конце диалога NPC выдает задание. Квест — это тоже класс данных.

    Когда игрок убивает врага, мы проверяем, есть ли активный квест с типом Kill. Если да, увеличиваем currentAmount. Если IsReached() возвращает истину, квест считается выполненным, и игрок может вернуться к NPC за наградой.

    Заключение

    Сегодня мы превратили наш боевой прототип в настоящую RPG. Мы научились:

  • Использовать ScriptableObjects для создания базы данных предметов.
  • Строить Инвентарь на основе списков и событий.
  • Реализовывать Интерфейсы для взаимодействия с миром.
  • Создавать Диалоги с использованием очередей.
  • Описывать структуру Квестов.
  • Теперь ваш герой может не только сражаться, но и жить в этом мире: собирать трофеи, общаться с жителями и выполнять их просьбы. В следующей, заключительной части курса, мы займемся полировкой игры: добавим звуки, эффекты частиц, главное меню и соберем финальный билд проекта.

    5. Полировка и релиз: добавление звуков, визуальных эффектов, система сохранений и сборка проекта

    Полировка и релиз: добавление звуков, визуальных эффектов, система сохранений и сборка проекта

    Поздравляю! Если вы читаете эту статью, значит, у вас уже есть работающая RPG. Ваш герой бегает, сражается, собирает предметы и выполняет квесты. Но пока ваша игра может ощущаться «сухой». Ей не хватает того, что разработчики называют Game Juice (Сок) — аудиовизуальной обратной связи, которая делает игру живой.

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

    Аудиосистема: Звук как половина атмосферы

    В Unity звук работает через взаимодействие двух компонентов:

  • Audio Listener (Слушатель): Это «уши» игрока. Обычно этот компонент висит на камере. В сцене должен быть только один слушатель.
  • Audio Source (Источник): Это объект, который издает звук (монстр, факел, меч).
  • 2D и 3D звук

    В настройках Audio Source есть ползунок Spatial Blend.

    * 2D (0.0): Звук звучит одинаково громко, где бы вы ни находились. Используется для музыки и интерфейса. * 3D (1.0): Громкость звука зависит от расстояния до слушателя. Используется для эффектов в мире.

    !Иллюстрация затухания звука в зависимости от дистанции.

    Математика затухания звука

    В реальном мире (и в Unity при настройке Logarithmic Rolloff) интенсивность звука падает обратно пропорционально квадрату расстояния. Это описывается законом обратных квадратов:

    Где: * — интенсивность звука в конкретной точке. * — мощность источника звука. * — математическая константа Пи (примерно 3.14159). * — расстояние от источника до слушателя.

    Это значит, что если вы отойдете от источника в 2 раза дальше, звук станет тише в 4 раза. В Unity вы можете настраивать кривую затухания (Volume Rolloff), чтобы звук не исчезал слишком быстро.

    Программное воспроизведение звуков

    Чтобы не создавать Audio Source на каждый чих, мы можем использовать метод PlayOneShot. Он идеально подходит для звуков ударов, шагов или сбора монет.

    Добавьте в скрипт PlayerCombat:

    Визуальные эффекты (VFX)

    Когда меч ударяет по врагу, игрок должен видеть результат. В Unity за это отвечает Particle System (Система частиц).

    Создание эффекта удара

  • Создайте систему частиц: GameObject -> Effects -> Particle System.
  • Настройте параметры:
  • * Duration: 0.5 (короткая вспышка). * Looping: Выключить (эффект должен проиграться один раз). * Start Speed: Высокая, чтобы искры разлетались. Emission: В разделе Bursts* добавьте одно событие с количеством 30 частиц. * Shape: Sphere или Cone.
  • Сохраните этот объект как префаб (перетащите из иерархии в папку Project) и удалите со сцены.
  • Инстанцирование эффекта

    Теперь вернемся к скрипту PlayerCombat. В момент нанесения урона (внутри проверки Physics.Raycast) мы создадим этот эффект.

    Система сохранений: JSON и Сериализация

    RPG — длинная игра. Игрок должен иметь возможность сохранить прогресс. Мы будем использовать формат JSON — это текстовый формат, удобный для чтения и компьютером, и человеком.

    Процесс превращения объектов игры (здоровье, позиция, уровень) в текст для записи в файл называется сериализацией.

    !Схема преобразования игровых данных в текстовый формат для сохранения.

    Подготовка данных

    Создайте класс, который будет служить контейнером для данных. Он не должен наследовать от MonoBehaviour.

    Менеджер сохранений

    Создайте скрипт SaveSystem.cs. Мы будем использовать встроенный класс JsonUtility.

    Теперь вы можете добавить кнопки «Сохранить» и «Загрузить» в ваше меню паузы и вызывать эти методы.

    Сборка проекта (Build)

    Ваша игра готова. Пришло время превратить её в приложение.

  • Настройка сцен: Откройте File -> Build Settings. Перетащите все ваши сцены (Главное меню, Уровни) в окно Scenes In Build. Убедитесь, что Меню стоит под индексом 0.
  • Player Settings: Нажмите кнопку Player Settings. Здесь вы можете:
  • * Установить название компании и продукта. * Загрузить иконку игры (Default Icon). * Настроить разрешение экрана.
  • Сборка: Выберите платформу (Windows/Mac/Linux) и нажмите Build. Выберите пустую папку, куда Unity сложит файлы игры.
  • > Никогда не сохраняйте билды внутри папки Assets вашего проекта. Создайте отдельную папку Builds в корневой директории проекта.

    Заключение курса

    Мы прошли огромный путь. Из пустого проекта мы создали живой мир. Мы разобрали: * Создание ландшафта и освещения. * Программирование движения и анимации. * Боевую систему, ИИ и характеристики. * Инвентарь, диалоги и квесты. * Звук, эффекты и сохранения.

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

    Спасибо, что были с нами на этом курсе. Удачи в разработке вашей игры мечты!