Основные концепции Unity для инженеров-программистов
Если вы пытаетесь заняться разработкой игр в качестве инженера-программиста, поиск учебных материалов с нужным уровнем контекста может оказаться сложной задачей. Вы, вероятно, столкнетесь с выбором между следующими материалами, знакомящими вас с базовыми концепциями C# и ООП, а также описывающими концепции Unity, или начав с расширенных руководств, и вам будет предоставлено дедуктивное определение основных концепций.
Чтобы восполнить этот пробел, я пишу серию статей под названием Unity for Software Engineers. Эта серия предназначена для людей, уже знакомых с программированием и архитектурой программного обеспечения, особенно для тех, кто лучше всех учится, как я: начиная с основных принципов и постепенно продвигаясь вверх.
Я начал свое путешествие в программирование около 17 лет назад, взяв Game Maker. Бесчисленные часы, потраченные на программирование небольших игр и инструментов, привели меня к большему увлечению программированием. В конце концов, я сосредоточился в основном на разработке программного обеспечения. От моих коллег я знаю, что это довольно распространенный путь, по которому многие из нас пошли в поисках программирования.
Тем не менее, с тех пор среда разработки игр значительно изменилась. Когда я взялся за Unity после долгого отсутствия в разработке игр, меня больше всего интересовало понимание основных концепций: каковы фундаментальные строительные блоки игры? Что мне нужно знать о том, как эти строительные блоки представлены в памяти или на диске? Как устроен идиоматический код? Какие модели предпочтительнее?
В первой статье серии мы сосредоточимся на этих первых двух вопросах.
Сцены
Сцена является самым крупным подразделением упорядочивания объектов в памяти. Сцены содержат объекты, составляющие вашу игру.
При базовом использовании одна сцена представляет один уровень в вашей игре, где одна сцена загружается в любой заданный момент. При более «продвинутом» использовании вы можете одновременно иметь две или более активных сцен. Сцены можно загружать аддитивно и выгружать. Загрузка нескольких сцен во время игры особенно удобно при построении огромного мира; Хранение удаленных областей на диске, а не в памяти, поможет вам не выходить за рамки бюджета производительности.
Каждый игровой объект в Unity должен находиться в сцене.
Игровые объекты
Game Object (в коде GameObject
) является одним из основных строительных блоков игры.
Игровые объекты могут представлять как физические вещи, которые вы видите в игре (например, игрока, землю, дерево, местность, огни, оружие, пулю, взрыв), так и метафизические объекты (например, менеджер инвентаря, многопользовательский контроллер и т. д.) в вашей игре.
У каждого игрового объекта есть положение и поворот. Для метафизических объектов это не имеет значения.
Игровые объекты могут располагаться друг под другом. Положение и поворот каждого объекта относительно его родительского объекта. Объект непосредственно в сцене относительно координат «мирового пространства».
Вы можете выбрать размещение своих объектов по многим причинам. Например, вы можете решить, что с организационной точки зрения имеет смысл поместить все объекты «окружения» (например, отдельные части, составляющие город или деревню) под пустым родительским объектом. Таким образом, они могут быть свернуты в виде сцены и легко перемещены вместе при создании игры.
Вложение игровых объектов также может иметь функциональное значение. Например, «Автомобиль» может быть объектом с кодом, который управляет скоростью и вращением автомобиля в целом. Но отдельные дочерние объекты могут представлять четыре колеса (они будут вращаться независимо), корпус автомобиля, окна и т.д. Перемещение родительского объекта автомобиля приведет к перемещению всех дочерних объектов, сохраняя их относительную ориентацию относительно родительского (и друг друга). Например, мы можем захотеть, чтобы игрок взаимодействовал с дверью отдельно от остальной машины.
Компоненты (и MonoBehaviors)
Каждый игровой объект состоит из компонентов.
Компонент реализует четко определенный набор поведения для выполнения GameObject. Все, что делает объект тем, чем он является, будет происходить из компонентов, из которых он состоит:
- У единственной «видимой» части автомобиля будет компонент Renderer, который его раскрашивает, и, вероятно, компонент Collider, который устанавливает границы столкновения.
- Если автомобиль представляет игрока, сам объект автомобиля может иметь контроллер ввода игрока, который принимает события ввода клавиш и преобразует их в код, перемещающий автомобиль.
Хотя вы можете написать большие и сложные Компоненты, которые соответствуют 1:1 объекту (например, компонент проигрывателя кодирует весь проигрыватель, а компонент врага кодирует врага в целом), обычно логику разбивают на упрощенные части. соответствующие индивидуальным чертам. Например:
- Все объекты со здоровьем, будь то игрок или враг, могут иметь компонент
LivingObject
, который устанавливает начальное значение здоровья, принимает урон и запускает событие смерти после его смерти. - У игрока может быть дополнительный компонент ввода, управляющий его движением, в то время как у врага может быть компонент AI, который вместо этого контролирует его движение.
Компоненты получают различные обратные вызовы на протяжении своего жизненного цикла, известные в Unity как сообщения. Примеры сообщений включают в себя OnEnable
/ OnDisable
, Start
, OnDestroy
, Update
, и другие. Если объект реализует метод Update()
, этот метод будет автоматически вызываться Unity в каждом кадре игрового цикла, пока объект активен и данный компонент включен. Эти методы можно пометить private
; движок Unity по-прежнему будет их вызывать.
Компоненты также могут предоставлять открытые методы, как и следовало ожидать. Другие компоненты могут использовать ссылку на компонент и вызывать эти общедоступные методы.
Активы
Активы - это ресурсы на диске, из которых состоит ваш игровой проект. К ним относятся сетки (модели), текстуры, спрайты, звуки и другие ресурсы.
При сериализации на диск ваши сцены представляются как активы, состоящие из игровых объектов внутри них. В следующем разделе мы также обсудим, как вы можете сделать игровые объекты, которые часто используются повторно, в актив, известный как Prefab.
Активы также могут представлять менее осязаемые вещи, такие как карты управления вводом, настройки графики, строковые базы данных i18n и многое другое. Вы также можете создавать свои собственные типы активов, используя ScriptableObjects.
Для вашего проекта, находящегося в стадии разработки, активы образуют ключевое представление кодовой базы вашего проекта вместе с вашим кодом.
Вложенные сборные блоки
Игровые объекты, их компоненты и их входные параметры существуют как отдельные экземпляры в сцене. Но что, если определенный класс объектов обычно повторяется? Такие объекты можно превратить в префаб, который фактически является объектом в форме актива.
Экземпляры префаба в сцене могут иметь локальные модификации, которые отличают его (например, если объект дерева является префабом, у вас могут быть экземпляры дерева разной высоты). Все экземпляры префаба наследуют и переопределяют данные из своих префабов.
Вложенные префабы
Начиная с Unity 2018.3, префабы могут быть вложены так, как вы ожидаете:
- Родительский объект с дочерними префабами может быть сам по себе префабом. В родительском префабе экземпляр дочернего префаба может иметь свои собственные модификации. В сцене создается вся иерархия префабов, а модификации, специфичные для сцены, могут накладываться поверх.
- Экземпляр префаба в сцене с его собственными локальными модификациями может быть сохранен как его собственный актив «Вариант префаба». Вариант - это сборный актив, который наследуется от другого сборного дома с применением дополнительных модификаций поверх.
Эти концепции составляют; например, сборный вариант вложенного сборного дома или сборный вариант сборного варианта.
Сериализация и десериализация
Ресурсы, сцены и объекты вашего проекта сохраняются на диске. При редактировании игры эти объекты загружаются в память и сохраняются обратно на диск с помощью системы сериализации Unity. При тестировании игры объекты и сцены в памяти загружаются через одну и ту же систему сериализации. Эта система также сопоставляет ресурсы в вашем скомпилированном пакете с загруженными / выгруженными объектами сцены в памяти.
Поток сериализации / десериализации Unity Engine загружает ресурсы с диска в память (в вашем проекте: для редактирования / тестирования; в игре, при загрузке сцены) и отвечает за сохранение состояния ваших отредактированных объектов и компонентов обратно в их сцены.
Таким образом, система сериализации также лежит в основе самого редактора Unity Editor. Для того чтобы MonoBehavior
принимал входные данные при построении и создании экземпляра в сцене, эти поля должны быть сериализованы.
Большинство основных типов Unity, таких как GameObject
, MonoBehavior
и ассеты, являются сериализуемыми и могут получать начальные значения при создании из редактора Unity. Общедоступные поля на вашем MonoBehavior
сериализованы по умолчанию (если они сериализуемого типа), а частные поля также должны быть помечены атрибутом [SerializeField]
для сериализации.
Вывод
Эти шесть концепций охватывают важные структурные элементы для создания архитектуры игр в Unity. Знание об этом и о том, как ресурсы на диске отображаются в представление в памяти, должно дать вам понимание, необходимое для выполнения некоторых из более сложных руководств.