Как сделать шутер на юнити 3д

Зомби-шутер на DOTS в Unity

Всем привет! Меня зовут Николай Запольнов, я преподаватель на курсах Unity Basic и Unity Pro в OTUS. И сегодня я хочу рассказать вам про, без преувеличения, будущее Unity — технологию DOTS.

В этой статье мы узнаем, что же такое этот DOTS, какие проблемы он решает и как применить его на практике.

Но начать, все же, стоит с теории.

DOTS (“Data Oriented Tech Stack” — технический стек, ориентированный на данные) — это новый подход к разработке игр на движке Unity. Впервые он был анонсирован в 2017 году, а некоторые его компоненты еще раньше — в 2016. В рамках этого технического стека Unity руководствуется слоганом “performance by default” (“производительный по умолчанию”): они создают оптимизированный и эффективный фреймворк в противоположность “классическому” Unity, где программист должен внимательно выбирать, какое API он использует, создавать пулы объектов и т.д.

Для обеспечения максимальной производительности, DOTS включает в себя множество компонентов. Так, например, Job System (Система задач) предоставляет удобный и простой API для многопоточного программирования. Но самым важным нововведением DOTS является использование паттерна Entity-Component-System (ECS).

Entity Component System

Одним из основных столпов классического объектно-ориентированного программирования является наследование. Дочерние классы, собственно, наследуют свойства и методы родительского класса, расширяя и дополняя их новыми возможностями. Такой подход позволяет переиспользовать код, но в больших проектах он также создает и проблему: построить подходящую иерархию объектов не всегда возможно. В результате, в проекте появляются так называемые божественные классы (god classes), реализующие огромный набор методов, часть которых используется одними дочерними классами, а часть — другими.

В качестве альтернативы наследованию была предложена композиция. В геймдеве такой подход часто называют Entity-Component (EC) и именно он применяется в “классическом” Unity. В паттерне EC сущности (entities, в Unity они реализованы классом GameObject) являются лишь контейнерами для компонентов. А компоненты, в свою очередь, реализуют конкретную функциональность и содержат в себе как код, так и данные. Это позволяет собирать каждую конкретную сущность из фрагментов функциональности, как из кубиков Лего.

Паттерн Entity-Component-System развивает эту парадигму еще дальше. Он предлагает оставить в компонентах только данные, а код вынести в системы. Это позволяет оперировать группой компонентов и выводит переиспользование кода на новый уровень. А еще, такой подход позволяет хранить данные компонентов в памяти последовательно. Это сильно увеличивает эффективность работы кеша на современных процессорах и, соответственно, повышает производительность.

Но довольно теории, давайте перейдем к практике!

Подготавливаем проект

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

Эта статья написана и проверена на Unity 2020.1.16f1. Вы можете использовать и другую версию, но тогда существует вероятность, что что-то не заработает. DOTS очень активно развивается и программные интерфейсы иногда меняются.

Начнем с пустого проекта (я использовал шаблон “3D” в Unity Hub). Итак, прежде всего нам потребуется добавить DOTS в наш проект. Делается это через менеджер пакетов, но просто так их не найти. Некоторое время назад авторы Unity убрали все preview-пакеты из общего списка, и теперь, чтобы их установить, необходимо нажать в верхнем левом углу пакетного менеджера кнопку “+” и в появившемся меню выбрать “Add package from git URL…”:

Потребуется установить следующие пакеты:

  • com.unity.entities — реализация паттерна Entity-Component-System в DOTS.
  • com.unity.physics — физический движок для DOTS.
  • com.unity.rendering.hybrid — гибридный рендерер для DOTS, выполняет роль “моста” между системой DOTS и стандартной архитектурой рендеринга Unity.

Установка этих пакетов также приведет к установке и других компонентов DOTS. Давайте кратко рассмотрим, что еще добавится в наш проект:

  • com.unity.burst — компилятор высокопроизводительного кода для C#.
  • com.unity.collections — альтернативные версии коллекций (список, очередь, словарь и т.д.), основанные на использовании памяти движка вместо сборщика мусора.
  • com.unity.jobs — система многопоточного программирования для DOTS. Позволяет легко распараллеливать код и автоматически отслеживать ошибки, возникающие при многопоточном программировании. Например, “условия гонки” (race conditions).
  • com.unity.mathematics — оптимизированная библиотека векторной математики взамен стандартных Vector2, Vector3 и т.д.

Кроме компонентов DOTS нам также пригодится пакет Cinemachine. Это очень удобный инструмент для управления камерами в Unity. Подробно останавливаться на нем сегодня я не буду, но крайне рекомендую ознакомиться, если вы про него еще не слышали. Устанавливаем:

Ну и наконец стоит добавить в проект пару наборов ассетов. Я буду использовать следующие бесплатные паки:

Познаем сущности

Для начала, давайте создадим в сцене плоскость, которая будет играть роль Земли. Я делаю это как обычно: щелкаю правой кнопкой мыши в окне Hierarchy и выбираю 3D Object⇨Plane:

Назначу ей материал зеленого цвета, чтобы она была больше похожа на траву:

Теперь у нас в сцене есть обычный GameObject, изображающий плоскость. Так причем же здесь DOTS? Пока что не причем. На текущем этапе развития технологии, сцену в Unity мы по-прежнему создаем на основе игровых объектов.

Но теперь у нас на вооружении есть новый компонент: ConvertToEntity. Добавив этот компонент в объект Plane, мы укажем Unity при запуске игры превратить его в сущность в системе ECS:

Компонент предлагает два режима преобразования: Convert and Destroy (выбран по умолчанию) и Convert And Inject Game Object. Выбор первого режима приводит к удалению игрового объекта после создания сущности, а при выборе второго игровой объект сохраняется. Мы пока оставим эту настройку как есть, т.е. будем уничтожать объект.

Давайте запустим игру и посмотрим, что получилось:

Итак, игровой объект Plane пропал из иерархии, но плоскость все же рисуется в игровом окне. Очевидно, что теперь она стала сущностью. Как можно убедиться в этом?

Unity предоставляет для этого удобный инструмент, который можно найти в меню Window⇨Analysis⇨Entity Debugger:

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

Выбрав конкретную систему, в правом столбце можно увидеть, какими конкретно сущностями она оперирует. А если выбран пункт All Entities, как на скриншоте, то мы увидим список абсолютно всех сущностей. В моем примере их всего две: WorldTime (стандартная сущность Unity, отслеживающая текущее время) и Plane — наша плоскость!

Если выбрать сущность Plane, инспектор покажет нам, какие компоненты она в себя включает:

Как видите, вместо стандартных компонентов Unity здесь используются совершенно другие, новые компоненты. Так, компонент Transform был заменен на три компонента: LocalToWorld, Rotation и Translation. Вместо MeshFilter и MeshRenderer используется компонент RenderMesh. А для физики добавился компонент PhysicsCollider.

Я покажу как пользоваться этими компонентами чуть позже. Пока же для нас важно обратить внимание на следующие моменты:

  • Сущности DOTS существуют в своем отдельном мире и никак не взаимодействуют с игровыми объектами.
  • Для стандартных компонентов Unity существуют аналогичные им по функциональности компоненты и системы DOTS (здесь важно отметить, что многие из них еще в разработке и не обладают всей полнотой возможностей стандартных компонентов)
  • Редактировать параметры компонентов во время исполнения игры в инспекторе нельзя. Что довольно-таки неудобно при отладке. Надеюсь это все-таки поправят.

Что за игра без игрока?

Давайте теперь создадим главного персонажа, которым будет управлять наш игрок. Я добавлю новый, пустой игровой объект и назову его Player. Сразу же добавлю туда компонент ConvertToEntity, чтобы не забыть про него.

Для удобства, я создам отдельный, вложенный игровой объект для внешнего вида игрока (т.е. содержащий 3d-модель персонажа). Давайте для начала используем простую капсулу (щелчок правой кнопкой в иерархии, 3D Object⇨Capsule). Чтобы она не проваливалась в землю, ей необходимо поставить Position.Y равным 1.

При создании капсулы, Unity сразу же создает и коллайдер. Но чтобы физика могла управлять нашим игровым объектом, потребуется добавить соответствующий компонент. Его я буду добавлять в родительский объект (Player) и вместо привычного RigidBody я добавлю компонент DOTS, который называется PhysicsBody:

В добавленном компоненте нужно поправить несколько параметров. Во-первых, массу (параметр Mass) стоит увеличить: я поставлю 70. Во-вторых, я сброшу параметр Angular Damping в 0. Поскольку у нас персонаж будет поворачиваться из кода, мы не хотим, чтобы физика замедляла это движение. Ну и наконец, я поставлю Gravity Factor равным 1.5. В моих экспериментах, если оставить этот параметр равным 1, физика воспринимается как на Луне.

Итак, у нас есть персонаж-капсула. Но как заставить его двигаться? Если помните, я говорил, что в ECS любая логика должна находиться в системах. Нам потребуется написать систему движения игрока. А чтобы система знала, какими сущностями она должна оперировать, мы создадим специальный компонент и назначим его объекту персонажа.

Код компонента ( Scripts/Components/PlayerComponent.cs ):

Очевидно, что он значительно отличается от привычных компонентов. Так, например, необходимо использовать библиотеку Unity.Entities вместо UnityEngine. Взамен класса создается структура. Родительский класс MonoBehaviour был заменен интерфейсом IComponentData. А еще в компоненте нет никаких методов!

Важно также обратить внимание на атрибут GenerateAuthoringComponent. Если его не добавлять, то в целом такой компонент тоже можно использовать. Но его нельзя будет создавать и редактировать в Unity. Именно благодаря этому атрибуту мы теперь сможем в инспекторе добавить наш новый компонент в игровой объект Player:

И даже параметры movementSpeed и rotationSpeed доступны для редактирования! Все, как мы привыкли. На скриншоте я уже проставил туда соответствующие значения (20 и 500).

Давайте теперь реализуем систему ( Scripts/Systems/PlayerMovementSystem.cs ):

Итак, наша система наследуется от класса ComponentSystem . Это не единственный возможный родительский класс для системы, на другие мы посмотрим чуть позже. Пока важно знать, что, наследуясь от этого класса, система будет работать только в основном потоке и не сможет использовать возможности Job System по распараллеливанию. Но поскольку я здесь обращаюсь к API Unity ( Time.DeltaTime и класс Input ), мне это и не пригодится.

Код системы располагается в перегруженном методе OnUpdate . Он будет вызываться каждый кадр, примерно как Update в привычных нам компонентах на основе MonoBehaviour .

С помощью метода Entities.ForEach , который будет нашей с вами основной рабочей лошадкой, я могу обработать все сущности, имеющие (в данном случае) компоненты PlayerComponent , LocalToWorld и PhysicsVelocity . Если хотя бы одного из этих компонентов у сущности нет, она не будет обработана этой системой.

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

Давайте запустим игру:

Система работает! Персонажем можно управлять! Но погодите, что же это? Почему капсула заваливается?

В стандартной физике Unity мы могли бы использовать параметр Freeze Rotation у Rigidbody, чтобы предотвратить падение персонажа. В физике DOTS такого параметра пока что, к сожалению, нет. Поэтому я создаем еще один компонент и систему, чтобы решить эту проблему.

Компонент ( Scripts/Components/FreezeVerticalRotationComponent.cs ) мне здесь нужен исключительно как маркер, чтобы обозначить системе, какие именно сущности она должна обрабатывать. Никаких дополнительных данных я в нем хранить не буду:

А вот код системы ( Scripts/Systems/FreezeVerticalRotationSystem.cs ):

Поскольку эта система не взаимодействует со стандартным API движка, я могу сделать ее многопоточной. Для этого вместо класса ComponentSystem используется родительский класс JobComponentSystem .

Теперь также поменялась и сигнатура метода OnUpdate . Теперь он принимает аргумент JobHandle и возвращает JobHandle . Эти хендлы позволят менеджеру правильно организовать параллельное выполнение этой системы с другими системами. Очень важно не забывать передавать эти хендлы, чтобы избежать возникновения условия гонки (race condition), когда две системы попытаются одновременно работать с одной и той же сущностью.

Здесь также используется Entities.ForEach , но обратите внимание, что дополнительно вызывается метод Schedule, который собственно и запускает выполнение кода нашей системы во вспомогательных потоках.

Добавим компонент FreezeVerticalRotationComponent к объекту Player в редакторе и запустим игру:

И теперь наш персонаж не заваливается.

Иллюзия жизни

Персонаж-капсула — это, несомненно, весело. Но веселее было бы, если бы наш главный герой был больше похож на человека, а главное — был анимирован.

К сожалению, система анимации на DOTS все еще находится на очень ранних этапах разработки и в данном проекте я ее использовать не буду. Воспользуюсь старым добрым Animator Controller.

Для начала, перетащу в качестве дочернего объекта в Player префаб TT_demo/prefabs/TT_demo_police из пакета ToonyTinyPeopleDemo и назначу ему заранее заготовленный контроллер. Я не буду подробно останавливаться на устройстве Animator Controller, приведу здесь лишь скриншот:

Также к объекту TT_demo_police я добавлю компонент ConvertToEntity , установив параметр Conversion Mode в Convert and Inject Game Object. Таким образом, при запуске игры для объекта 3d-модели также будет создана сущность, но, в отличие от игрока и капсулы, сохранится и GameObject . Он, правда,окажется в корне (так как родительский объект превратился в сущность без сохранения GameObject ):

И тут есть один нюанс. Если сейчас запустить игру, мы увидим, что при движении нашего персонажа игровой объект с 3d-моделью будет оставаться на месте:

Чтобы это поправить, я добавлю новый компонент и систему.

Компонент ( Scripts/Components/CopyTransformComponent.cs ) также выполняет роль простого маркера:

А система ( Scripts/Systems/CopyTransformSystem.cs ) просто осуществляет копирование положения сущности в компонент Transform игрового объекта:

Важным нововведением здесь является добавление аргумента Entity entity в лямбду. Этот аргумент передается без спецификатора ref , поскольку он по сути является лишь числовым идентификатором сущности и его нельзя менять. Но зато его можно использовать совместно с классом EntityManager для манипуляции сущностями и, в данном случае, для получения ссылки на компонент Transform у связанного с сущностью игрового объекта (привязку осуществляет компонент ConvertToEntity при конвертации, поскольку был выбран режим Convert And Inject Game Object ).

Теперь я добавлю компонент CopyTransformComponent к игровому объекту TT_demo_police . Игровой объект Capsule я оставлю (так как в нем находится коллайдер), но отключу у него MeshRenderer , чтобы капсула не рисовалась на экране.

И да, теперь наш персонаж двигается.

Осталось добавить 3d-модельке игрока анимацию. Как вы, наверное, уже догадались, потребуется создать еще один компонент и систему.

N.B. В начале работы над игрой, использующей паттерн ECS, требуется создавать довольно большое количество систем и компонентов, и может показаться, что это лишняя работа по сравнению с паттерном EC. На самом деле, это не так. Преимущества ECS полностью проявляются, когда накоплена некоторая “критическая масса” компонентов и систем. В некоторой мере мы это увидим и в сегодняшней статье, когда будем реализовывать врагов.

Ничего особенно нового здесь нет. Стоит обратить внимание, что компонент AnimatedCharacterComponent следует добавлять на родительскую сущность ( Player ) — ему требуется получать значения скорости из компонента PhysicsVelocity физического движка. А вот аниматор прикреплен к дочерней сущности ( TT_demo_police ). Чтобы получить доступ из одной сущности к другой, я просто использую переменную типа Entity в компоненте AnimatedCharacterComponent . Благодаря механизму ConvertToEntity , в редакторе сцены я смогу проставить туда игровой объект, а при запуске игры он автоматически сконвертируется в ссылку на соответствующую сущность:

Запустив игру, убеждаемся, что теперь анимация работает:

А я все гляжу, глаз не отвожу

Я сейчас ненадолго отвлекусь и наведу немного красоты: добавлю контента в уровень и настрою камеру.

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

Камеру же я настрою с использованием Cinemachine . Подробно останавливаться на этом я не буду, приведу лишь пример настройки.

Для начала, я создам отдельный пустой игровой объект внутри TT_demo_police и поставлю его примерно на уровень головы — он будет использоваться для “прицеливания” камеры. Назову его CameraTarget .

Теперь можно создать виртуальную камеру. Для этого выберу пункт меню Cinemachine⇨Create Virtual Camera (если этого меню у вас нет, проверьте, установили ли вы пакет Cinemachine ).

В инспекторе для созданной виртуальной камеры проставлю TT_demo_police в поле Follow и CameraTarget в поле Look At . В разделе Body поставлю Follow Offset X=0, Y=9, Z=-15 и Yaw Damping в 0.25 .

Стреляй, Глеб Егорыч!

Бегать по карте — это здорово. Но шутер не был бы шутером, если бы там нельзя было стрелять. А у нас все еще нельзя. Нужно срочно это исправлять!

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

Сам пистолет прикреплен к анимированному скелету и его легко найти в иерархии объекта TT_demo_police :

Я создам внутри пистолета пустой объект (назову его GunHole) и задам ему положение (-0.1174, 0, 0.394) и поворот (0, 0, 90). Этот объект я буду использовать как референс для кода, создающего пули.

Но есть небольшая проблема: так как TT_demo_police (родительский объект) уже содержит в себе ConvertToEntity с режимом Convert And Inject Game Object , я не смогу сделать то же самое с моим вновь созданным объектом, Unity разрешает только одну такую конвертацию для иерархии объектов.

Поэтому, я создам новый объект Shooter внутри объекта Player и прикреплю к нему небольшой компонент на основе MonoBehaviour ( Scripts/Shooter.cs ):

И пропишу в него ссылку на GunHole в инспекторе.

А поскольку Shooter находится вне объекта TT_demo_police , я могу также добавить в него компонент ConvertToEntity :

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

Поэтому я создам префаб из двух игровых объектов: родительский будет содержать в себе компоненты ConvertToEntity и PhysicsBody , а дочерний — меш и коллайдер капсулы:

Из важного: коллайдер у пули настроен как триггер, а в параметры PhysicsBody внесены небольшие изменения: Linear Damping выставлен в 0, чтобы пуля не теряла скорость со временем, и Gravity Factor также выставлен в 0.

В объект Shooter также добавлю компонент BulletPrefabComponent ( Scripts/Components/BulletPrefabComponent.cs ):

Этот компонент позволит нам получить доступ к префабу из ECS-кода, а также — задать скорость пули (сразу можно ее проставить в инспекторе, я использовал значение 30).

И еще один компонент я буду проставлять непосредственно на пули ( Scripts/Components/Bullet.cs ):

Здесь параметр speed будет определять вектор направления движения пули и ее скорость, а флаг destroyed будет использоваться для обозначения пуль, столкнувшихся с препятствием. Зачем нужен этот флаг и как он используется я объясню чуть дальше.

Теперь для выстрелов нам потребуется система ( Scripts/Systems/PlayerShootingSystem.cs ):

Если сейчас запустить игру, мы увидим, что при выстреле пули действительно появляются:

Но они не двигаются! Как исправить? Правильно — завести систему ( Scripts/Systems/BulletSystem.cs ):

Как видите, тут все очень просто: задаем пулям постоянную скорость и пусть себе летят.

Ожившие мертвецы

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

Я создам в корне сцены пустой игровой объект Zombie и настрою его по аналогии с главным героем. Сразу положу внутрь префаб TT_demo/prefabs/TT_demo_zombie . Также создам капсулу ( Position 0, 1, 0 ) и сразу отключу у нее MeshRenderer . В сам объект Zombie добавлю компоненты PhysicsBody , FreezeVerticalRotationComponent , AnimatedCharacterComponent и ConvertToEntity . Также компонент ConvertToEntity надо добавить и в объект TT_demo_zombie , указав режим Convert And Inject Game Object . Туда же нужно добавить и CopyTransformComponent . У PhysicsBody поставлю Mass=70 . В общем, очень похоже на настройку объекта Player , только без Shooter .

Приятно, что большинство компонентов и систем уже созданы. Но потребуется создать еще несколько компонентов, уникальных для зомби.

Прежде всего, нужно добавить врагу жизни ( Scripts/Components/HealthComponent.cs ):

И создадим систему ( Scripts/Components/AnimatedCharacterDeathSystem.cs ), которая будет отыгрывать анимацию смерти персонажа, когда счетчик жизней достигнет 0:

Для проверки я добавлю зомби компонент HealthComponent с количеством жизней 0 и запущу игру. Зомби должен сразу умереть:

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

Для этого мне потребуется самая сложная в этой статье система ( Scripts/Systems/BulletDamageSystem.cs ). Давайте сначала взглянем на нее, а потом будем разбираться:

Первая (и весьма важная) часть — это структура CollisionEventSystemJob . Она представляет собой задачу для системы Job System . В эту задачу физический движок передает перечень столкновений между физическими объектами. Код задачи в методе Execute проверяет, есть ли в одном из столкнувшихся объектов компонент BulletComponent . Если, действительно, один из объектов — пуля, то ей проставляется флажок destroy , а у второго объекта вычитаются жизни (если, конечно, у него есть соответствующий компонент; столкновение с деревом приводит просто к уничтожению пули).

Стоит обратить внимание на два момента: во-первых, обращение к компонентам происходит через класс ComponentDataFromEntity . Это нужно, потому что задача выполняется параллельно и движок должен отслеживать обращения к компонентам и не допускать одновременной работы с одним и тем же компонентом из разных потоков. Во-вторых, по той же причине, нельзя уничтожать пули сразу при обнаружении столкновения. Вместо этого, у пули проставляется флажок, который проверяется уже в безопасном окружении, где компонент может быть удален.

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

Беги, Лола, Беги!

Последняя важная составляющая логики врага, которая у нас все еще отсутствует — это движение. Давайте же реализуем охоту на игрока!

Для поиска пути я буду использовать технологию NavMesh . Опять же, я не буду останавливаться на ней подробно, скажу лишь, что запечь NavMesh можно в окне Navigation , которое можно открыть через меню Window⇨AI⇨Navigation .

Я создам внутри игрового объекта Zombie пустой объект NavMeshAgent и добавлю в него компонент NavMeshAgent . Также я добавлю компонент ConvertToEntity с режимом Convert And Inject Game Object .

В дополнение к этому, мне потребуется новый компонент NavMeshAgentComponent ( Scripts/Components/NavMeshAgentComponent.cs ):

Единственный параметр здесь — это сущность, которую этот NavMeshAgent будет двигать. Добавив этот компонент в дочерний объект NavMeshAgent , в качестве moveEntity я укажу объект Zombie .

Еще один новый компонент ( Scripts/Components/FollowTargetComponent.cs ):

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

Последним штрихом будет написание соответствующей системы ( Scripts/Systems/FollowPlayerSystem.cs ):

Конец

Сегодня мы с вами познакомились с платформой DOTS и паттерном ECS. Надеюсь, мне удалось заинтересовать вас этими технологиями и показать, как их использовать в реальном игровом проекте.

Шутер от первого лица в Unity. Часть 1 — создание проекта

В 1-й части урока создаём проект и узнаём немного теории о том, что такое Raycast.

Шутер от первого лица с использованием Raycast в Unity. За основу взят официальный урок с сайта Unity Let’s try: Shooting with Raycasts.

Добавить комментарий Отменить ответ

Наши проекты

Творческое программирование для всех! (игры и анимация на Scratch)

ЦЕНТР СФЕРА ТВОРЧЕСКОГО ПРОГРАММИРОВАНИЯ

Индивидуальный предприниматель Елисеева Ольга Евгеньевна
Местонахождение: Минск, Беларусь
Режим работы: онлайн
УНП 191277000
Р/с BY19UNBS30131116830040001933,
в ЗАО «БСБ Банк», РКЦ № 1, г.Минск, пл.Свободы, д.4
Код банка: UNBSBY2X

Как сделать Шутер на Unity за 30 минут

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

Для начала нам потребуются стандартные ассеты, которые мы можем скачать в Ассет Стор. Открываем Asset Store, вбиваем в поисковую строку Standard Assets. Создаем Plane. Растягиваем его площадь. В папке Character заходим в первую папку и в папке префаб перемещаем на сцену первый префаб. Так как у персонажа есть камера, основная камера нам не нужна, поэтому удаляем ее. Снова переходим в Ассет Стор, выбираем категории и жмем на Props.

шутер на юнити
Перемещаем префаб оружия на сцену и настраиваем его расположение.

шутер +на unity
Если оружие искажено, отражается не полностью, кликаем в иерархии на камеру и в инспекторе в Culling Mask — 0.1.

шутер 3д юнити
В иерархии перемещаем оружие в камеру.

  • урон — damage
  • сила стрельбы — fireSpeed
  • объект камеры — cam
  • дальность стрельбы — range
  • Physics.Raycast — это и есть луч. Далее указываем, откуда будет луч исходить. cam.transform.forward — направление луча.
  • out hit — результат выпуска луча.
  • range — ограничиваем выстрел

unity создание шутера
Теперь нам нужно вызвать эту функцию, для этого в Update пишем: если нажали ЛКМ, то вызываем функцию выстрела.

unity создаем шутер
Запускаем и проверяем.

  • префаб пули — bull;
  • след от пули — trace;
  • точка спавна — spawnBull;
  • звук — shot;
  • компонент воспроизведения — audioShot;
  • сила force = 310;

2д шутер на юнити
Воспроизведение системы частиц (следа от пули).

2д игра на unity
И спавн пули.

2d шутер +на unity
Далее переходим в Юнити, создаем пустой объект в пистолете, это и будет точка спавна, добавляем ей иконку.

как сделать шутер на юнити
Настраиваем расположение, ставим ее в начало дула. Теперь в папке ParticleSystem выбираем префаб Flare и перемещаем так же к дулу. В иерархии систему частиц перемещаем на точку спавна. Снова выбираем систему частиц и настраиваем эффект, нам нужно убрать две галки Looping и Play Awake. Делаем так же и во вложенных объектах частиц. Это позволит проигрывать эффект один раз.
На оружие в инспекторе добавляем компонент AudioSource. Теперь заполняем скрипт:
Cam — добавляем камеру.
Bull — находим в проекте префаб пули.
Trace — добавляем созданый эффект из иерархии.
Spawn Bull — точка спавна.
Shot — нажимаем на кружок и выбираем звук.
AudioShot — добавляем оружие потому что, на нем есть этот компонент.

как сделать шутер +на unity
Создадим отдельный скрипт для пули и в нем объявлим скорость пули. Далее прикладываем силу и уничтожаем ее через 0.5 секунд. Перемещаем скрипт на префаб пули.

как делать игры на unity
Также на префаб добавляем Capsule collider и ставим галку isTrigger. Теперь создадим новый скрипт, который будет уничтожать объект, в который мы попали.

создание 3d игры на unity
Нажимаем в окне проекта Юнити на кнопку All prefab, находим любой объект врага. Перемещаем его на сцену. Если на нем есть скрипты, отключаем их, сняв галку. Теперь переместим наш скрипт на врага. Чтобы скрипт сработал, на пулю нужно добавить тег bull. Создаем тег.

2д игра на unity
И назначаем его префабу пули. Запускаем и проверяем. Далее добавим силу: когда пуля будет попадать в объект, на него будет воздействовать сила. Переходим в скрипт gunManager, где у нас основная функция выстрела. Переменная силы у нас уже объявлена, нам осталось только прописать воздействие. Проверяем, есть ли физика у объекта. Если да, то мы прикладываем силу.

игру unity 3д
Сохраняем и проверяем.

Вот и все! Если вы хотите поближе познакомиться с разработкой игр на Unity 3D и программированием на языке C#, приходите к нам на курс. Мы в школе «Пиксель» учим детей 10-14 лет разбираться во всех инструментах Юнити, писать скрипт на Си Шарп, создавать многоуровневые сложные игры. Присоединяйтесь!

Создание FPS шутера на движке Unity

Игровой движок Unity позволяет делать игры различной сложности и жанра. В этой статье мы расскажем про создания FPS шутера прямиком из Asset Store.

Движок Unity славиться бесконечными возможностями для творчества, а также его отличным дополнением является их официальный магазин Asset Store .

В Asset Store находится большое количество различных плагинов, которые позволяют новичкам создавать профессиональные игры, используя различные готовые решения. Большинство из них платные, хотя изредка можно попасться на потрясные бесплатные ассеты.

Для создания нашего 3D шутера мы будем использовать готовый ассет из магазина, который называется FPS Starter Kit — Pro :

На данный момент стоимость ассета составляет 20 $ . Вы можете посчитать что это много, но поверьте это не так, ведь за эту цену вы получаете полноценную 3D игру, которая к тому же может быть экспортирована под различные платформы. И сейчас мы вам расскажем что можно сделать с этой игрой.

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

Вы сможете сразу протестировать игру зайдя в папку Scene -> Demo . Перед вами откроется игра, в которой будет изначальное меню, а в дальнейшем меню проигрыша, а также сам игровой процесс: оружие, противники, карта игры и, конечно же, сам игрок.

  1. Легкость в настройке. Ассет предназначен для работы как для опытных пользователей, так и для новичков в этом деле.
  2. Поддержка мультиплатформенности. Вы сможете экспортировать игру под все популярные платформы.
  3. Геймпады. Весь игровой процесс поддерживает Xbox One/360 контроллер, Dualshock 4/3 и многие другие.
  4. ИИ. Разумный искусственный интеллект для врагов.
  5. Детальная документация, множество оружия, различные враги, поддержка разработчиков и много другого.

Сам 3D шутер вы сможете переделать под себя, при этом вся игровая механика и многие стандартные вещи уже будут сделаны и готовы к использованию. К примеру, меню со всеми опциями можно просто оставить без изменений:

Заключение

FPS Starter Kit — Pro является отличным ассетом, который позволит вам создать быстро и без особых усилий современный 3D шутер. Этот шутер будет обладать множеством необходимых аспектов как для игры этого жанра!

Больше интересных новостей

6 лучших расширений VS Code для организации задач и кода6 лучших расширений VS Code для организации задач и кода
10 перспективных IT-профессий ближайших лет10 перспективных IT-профессий ближайших лет
Технология Tor и её применение в Tor браузереТехнология Tor и её применение в Tor браузере
5 лучших книг для изучения языка PHP5 лучших книг для изучения языка PHP

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *