unity создание объекта через скрипт
Создание объектов
Некоторые игры имеют постоянное количество объектов на сцене, однако обычно персонажи, пули, сокровища и другие объекты создаются и удаляются во время игры. В Unity, игровой объект (GameObject) может быть создан через функцию Instantiate, которая делает копию существующего объекта. Объект, который мы будем клонировать, должен быть prefab’ом и сохранен в папке Resources.
Сейчас ты напишешь пару скриптов, с помощью которых можно научиться создавать (spawn’инть) игровые объекты, например, для того, чтобы реализовать механику вот такой ловушки:
Ловушка
Подготовка
Тебе понадобятся четыре игровых объекта и скрипт, с которым ты уже знаком:
Stone
По нашему плану нам понадобятся камни, которые будут создаваться над головой Игрока. Выбери 3D-модель, которая тебе понравилась, добавь ей компоненты Rigidbody и два коллайдера: Capsule и Box. Box коллайдер должен быть чуть больше, чем Capsule, а также иметь включенным свойство Trigger.
После этого добавь этому игровому объекту скрипт OnTriggerSceneLoader и укажи в его свойствах название текущей сцены (а еще не забудь добавить ее в Build Settings).
Stone и его компоненты
Не забудь сохранить объект Stone, как prefab, в папке Resources!
Программирование
Тебе понадобятся два новых скрипта, чтобы все работало как нужно: Spawner.cs и TrapSwitch.cs
Spawner
Как мы уже говорили, в Unity есть функция Instantiate, которая делает копию существующего объекта:
В нашем случаем наш объект будет физическим, так что ты можешь сразу объявить Rigidbody, также понадобится переменная, в которой ты будешь указывать необходимое количество клонов:
Теперь нужно написать публичный метод, который ты будешь вызывать скриптом TrapSwitch.cs, стандартные методы Update() и Start() нам не понадобятся, так что их можно удалить:
Чтобы выполнить функцию Instantiate несколько раз, используй цикл, например, do while:
Технически, скрипт готов, но, если оставить все как есть, то во время выполнения метода Spawn(), практически, одновременно в одной точке появятся все amount (число) клоны. Из-за того, что наши клоны содержат в себе компоненты Rigidbody и коллайдер, клоны просто разлетятся в разные стороны, что выглядит не очень. При этом, шанс, что хотя бы один клон-камень попадет в Игрока будет очень низок. Поэтому добавь немного рандома и сделай так, чтобы каждый следующий камень создавался выше предыдущего на i:
Теперь все работает как нужно. Продолжим.
TrapSwitch
TrapSwitch будет размещен на объекте с триггером, когда Игрок будет его касаться, TrapSwitch будет запускать метод Spawn() у объекта Spawner. Напомним про коллайдеры и триггеры:
Сейчас тебе понадобиться метод OnTriggerEnter. Он выполняется, когда объект только вошел в зону триггера один раз. Создай такой скрипт:
Ты собираешься взаимодействовать с двумя игровыми объектами и объектом Spawner. Их нужно объявить:
Теперь необходимо убедиться, что объект, который войдет в триггер является Игроком. Это можно сделать, используя тег, как в OnTriggerSceneLoader:
Теперь последовательно напиши все необходимые команды внутрь условия: удаление (уничтожение) объекта TrapOn, включение объекта TrapOff, выполнение метода Spawn() и удаление (уничтожения) себя.
Все скрипты написаны. Поздравляем! Осталось правильно разместить все объекты на сцене и не забыть указать им друг на друга.
Unity3d. Уроки от Unity 3D Student (B04-B08)
Предыдущие уроки вы можете найти в соответствующем топике.
Теперь в каждом посте в скобках (в конце) будут указываться номера уроков. Буква в начале номера обозначает раздел (B-Beginner, I — Intermediate).
PS: Если вы не проходили предыдущие уроки, очень рекомендую их пройти, т.к. последующие изредка на них ссылаются.
Базовый Урок 04 — Уничтожение объектов
В уроке рассказывается как удалять объекты со сцены, использую команду Destroy (уничтожить).
Создайте пустую сцену и добавьте в нее сферу (GameObject->Create Other->Sphere) и куб (GameObject->Create Other->Cube). Куб назовем “Box”. Расположите объекты как показано на рисунке ниже.
Добавьте C#-Скрипт (Project View->Create->C# Script) и назовите его Destroyer. Как уже говорилось, при создании C#-скрипта Unity создает некий каркас, состоящий из подключенных библиотек и основного класса (используемого скриптом) с методами Start() и Update(). В Базовом Уроке 02 (основы ввода) использовался метод Update(), который вызывается каждый кадр. В данном случае мы воспользуемся методом Start(), который выполняется сразу после загрузки сцены. Добавим в тело метода Start() функцию Destroy() и передадим в нее gameObject, указав таким образом, что скрипт должен уничтожить объект, компонентом которого он является:
Добавим скрипт к сфере. Сделать это можно несколькими путями. Перетащив скрипт из Project View на сферу в Scene View.
Или на имя объекта в Hierarchy.
Так же можно выбрать сферу и добавить скрипт через меню компонентов (Component->Scripts->Destroyer) или просто перетащив скрипт в Inspector View выбранного объекта.
Снова выберите сферу и убедитесь, что среди компонентов присутствует ваш скрипт.
Нажмите на Play и вы увидите, что сразу после загрузки сцены сфера исчезает.
Давайте теперь попробуем уничтожить другой объект. Для этого нам понадобится статический метод Find класса GameObject. Заменим код в методе Start() следующим:
Примечание от автора перевода: Обратите внимание, что во втором случае мы передаем значение, вызывая статическую функцию, поэтому пишем имя класса (GameObject — с большой буквы), в то время как в первом мы передаем объект этого класса (gameObject — с маленькой буквы). В противном случае компилятор выдаст ошибку:
error CS0176: Static member `UnityEngine.GameObject.Find(string)’ cannot be accessed with an instance reference, qualify it with a type name instead
что переводится как:
“статический член UnityEngine.GameObject.Find(string) не может быть доступен по ссылки экземпляра (класса), вместо этого определите (вызовите) его с именем типа.”
Сохраним изменения в коде скрипта. Скрипт не требуется убирать со сферы и добавлять к нашему кубу, т.к. назависимо от того, к какому объекту он теперь прикреплен, скрипт будет искать любой объект (на сцене) с именем Box. Нажмем Play и увидим как теперь сфера остается в сцене, а куб пропадает.
Что делать, если нам требуется уничтожить объект не сразу, а спустя какое-то время? Это можно сделать передав значение во 2ой параметр функции Destroy:
Нажмите Play и убедитесь, что куб изчезает через 3и секунды после того, как сцена целиком загрузится.
Дополнительные материалы:
Базовый Урок 05 — Реализация создание объектов
В уроке рассказывается как создавать объекты в сцене в реальном времени (runtime), используя префабы и команду Instantiate (инстанциирование)
Если вы хотите добавлять объекты на сцену, когда сцена уже загружена, то вам требуется использовать скрипты, а точнее команду Instantiate().
Загрузите сцену из Базового урока 03 (Префабы) или создайте такую же новую. В нашей сцене присутствует префаб BouncyBox.
Нажмите Play и убедитесь, что куб по-прежнему падает и отталкивается от поверхностей.
Теперь удалите со сцены экземпляр BouncyBox.
После этого добавьте пустой объект (напоминаю, GameObject->Create Empty или Ctrl + Shift + N в Windows, Cmd + Shift + N в MacOS). Расположите его примерно в том месте, где раньше был экземпляр BouncyBox.
Создадим C#-Скрипт и назовем его Creater. Начнем редактирование скрипта. Заведем открытую (public) переменную типа GameObject и назовем ее thePrefab. Модификатор public требуется указывать, если, например, вы хотите передавать значение переменной через Inspector View. После чего в теле функции Start() создадим еще один GameObject (с именем instance) и проинициализируем его значением с помощью статической функции Instantiate().
Рассмотрим метод Instantiate() подробнее.
Метод клонирует объект original с заданными вектором положения (position) и кватернионом поворота (rotation).
Тип Vector3 является обычным 3х компонентым вектором (аналогично вектору из R 3 ).
Тип Quaternion — кватернион, задающий поворот объекта.
Добавьте скрипт к пустому объекту (c именем GameObject).Напоминаю, поскольку thePrefab объявлен с модификатором public, вы можете задавать его начальное значение прямо в Inspector View (у соответствующего компонента, то есть в нашем случае это Creator у GameObject’а). Перетащите наш префаб в место указания значения (или выберете его из списка, кликнув на кружок справа).
Нажмем Play и увидим, что на сцене появился наш прыгающий кубик.
Но наш кубик прыгает просто вверх и вниз, потому что не имеет начального угла поворота. Выберите GameObject и поверните его под небольшим углом.
Теперь, нажав Play, вы увидите, что кубик падает и отталкивается под различными углами.
Дополнительные материалы:
Базовый Урок 06 — Простой таймер
В данном уроке рассказывается как в Unit при помощи скриптов
создавать простой таймер, используя Time.deltaTime и переменную типа float.
Воспользуемся сценой из предыдущего урока (с пустым игровым объектом,
генерирующим экземпляры префаба, т.е. BouncyBox).
Создадим С#-скрипт и назовем его Timer. Добавим переменную myTimer, и напишем следующий код.
Сохраняем скрипт и переключаемся назад в Unity. Добавим скрипт к объекту GameObject.
Напомню, т.к. myTimer объявлена открытой (public), то в Inspector View вы можете менять ее начальное значение.
Жмем Play. Как только значение myTimer упадет до нуля, в статус баре вы увидите строку GAME OVER. Значение переменной myTimer будет продолжать опускаться (это можно увидеть в Inspector View).
Для того, чтобы переменная myTimer не опускалась ниже нуля, добавим еще одно ветвление в функцию Update(), в итоге мы получаем следующий код:
Нажмем Play и проследим за поведением переменной myTimer. Когда ее значение будет достаточно близким к нулю, то оно перестанет изменяться.
Дополнительные материалы:
Базовый Урок 07 — Основы движения
В уроке рассказывается, как двигать объекты c помощью функции transform.Translate.
Создадим сцену с кубом, камерой и источником света.
Создадим новый C#-скрипт и назовем его Move.
Поскольку движение должно быть непрерывно во времени, то основной код будет располагаться в методе Update(). Вызовем функцию Translate, объекта transform и передадим ей в качестве параметра Vector3(0, 0, 1). Получим следующий код:
Разберемся подробнее в коде. Тут transform — это объект класса Transform, привязанный к нашему объекту. Метод Translate() двигает объект вдоль вектора на расстояние равное его длине (параллельный перенос).
Сохраним наш скрипт и добавим его к нашему кубу. Нажмите Play и увидите как куб стремительно улетает вдоль оси Oz.
Давайте уменьшим скорость движения, например, умножив наш вектор на Time.deltaTime, то есть:
Нажмите Play и убедитесь, что куб начинает двигаться заметно медленнее.
Можно сделать наш скрипт более удобным в использовании, если скорость задать не фиксированным вектором, а через переменную. Заведем public переменную типа float и назовем ее speed. С помощью этой переменной можно будет задавать начальную скорость через Inspector View (по умолчанию она будет равна 5.0f):
Сохраним скрипт и убедимся, что в Inspector View у компонента Move появилась переменная Speed.
Посмотрите, как будет меняться скорость движения нашего объекта в соответствии с заданным начальным значением этой переменной. Например, при Speed = 3 скорость объекта не очень быстрая, но и не медленная.
Примечение: Для выражения Vector3(0.0f, 0.0f, 1.0f) существует короткая (но видимо чуть более медленная, если не прав, прошу поправить) запись Vector3.forward.
Кусок кода из обертки:
Дополнительные материалы:
Базовый Урок 08 — Основы движения с помощью силы.
В уроке рассказывается как c помощью приложения силы двигать физическое тело (Rigidbody).
Если у вас на сцене есть объект с компонентом Rigidbody, то нужно задавать ему движение с помощью приложения силы (передав таким образом все расчеты движения физическому движку игры). В противном случае вы можете начать конфликтовать с физикой объекта. Мы по-прежнему используем сцену из Базового урока 03.
Создадим C#-скрипт и назовем его Force. В методе Start() вызовем метод AddForce() компонента rigidbody (cвязанного с нашим объектом) и передадим ему вектор приложенной силы Vector3(0.0f, 0.0f, power). В классе заведем переменную типа float с именем power и значением, по умолчанию равным 500.0f:
Сохраним скрипт и добавим его к нашему объекту (или префабу). Теперь, если нажать Play, вы увидите как куб падает не вниз а под углом, из-за воздействия силы приложенной вдоль оси Oz.
Unity: знакомство со Scriptable Objects
В этом туториале вы узнаете, как создавать и использовать Scriptable Objects в Unity. Scriptable Objects помогут усовершенствовать ваш рабочий процесс, снизить объём занимаемой памяти и даже позволят разделить архитектуру кода.
Согласно документации Unity, ScriptableObject — это код класса, позволяющий создавать в игре Scriptable Objects для хранения больших объёмов общих данных, не зависящих от экземпляров скриптов.
Существует множество причин для использования Scriptable Objects в Unity. Они могут снизить объём используемой под каждый дополнительный префаб памяти, потому что по своей сути Scriptable Object следуют паттерну разработки Flyweight.
Ещё одно преимущество Scriptable Objects, которое будет основной темой этого туториала, заключается в их использовании для удобной пересылки данных. Мы рассмотрим это свойство на примере создания лавки торговца мечами, в которой будут отображаться параметры, цены и описания различных мечей.
Примечание: в этом туториале подразумевается, что вы знакомы с редактором Unity. Вы должны разбираться в том, как править код в редакторе кода и иметь базовые знания C#. Если вам нужно повысить свои навыки Unity, изучите другие туториалы по Unity.
Приступаем к работе
Начнём с загрузки материалов, которые нам потребуются.
Распакуйте скачанный файл в удобное для вас место и откройте в Unity проект Scriptable Object Tutorial-Starter.
Вы должны увидеть следующую папку, созданную как часть заготовки проекта:
Создание Scriptable Object
Для начала перейдите в сцену Sword Merchant. Она должна выглядеть следующим образом:
Подготовка Scriptable Object
Настало время для создания первого Scriptable Object!
В папке Scripts создайте новый скрипт под названием SwordData. Этот класс будет использоваться как контейнер для всех данных мечей, отображаемых в лавке торговца мечами.
Внутри этого класса начнём с наследования из ScriptableObject вместо MonoBehaviour :
Это действие сообщает Unity, что мы по-прежнему хотим использовать возможности и методы Unity, как обычный MonoBehaviour, но нам больше не нужно прикреплять этот скрипт к GameObject. Вместо этого он будет обрабатываться как любой обычный ассет, который можно создавать аналогично созданию префаба, сцены или материала.
Заполним скрипт сериализированными полями, в которых будут содержаться все данные, соответствующие информации, отображаемой в UI Sword Merchant.
В Unity атрибут SerializeField позволяет иметь частные переменные скрипта, доступные в Инспекторе. Он позволит задавать значения в редакторе, не предоставляя доступ к переменной из других скриптов.
Каждому мечу потребуется собственная уникальная реализация Scriptable Object SwordData. Но прежде чем мы сможем создать эти реализации, нам нужно добавить Scriptable Object в Asset Menu.
Добавим наш Scriptable Object в Asset Menu, добавив к классу SwordData следующий атрибут:
Также можно нажать правой клавишей мыши в окне Project и тоже увидеть новый ассет Sword Data:
Добавление данных
Упорядочим проект, создав в папке Scripts папку с названием Scriptable Objects, а внутри этой папки — ещё одну папку с названием Sword Data.
Внутри только что созданной папки Sword Data folder создадим наш первый ассет Sword Data.
У нового ассета Sword Data по-прежнему должно быть указанное ранее имя по умолчанию fileName. Выберите ассет и дублируйте его шесть раз (Ctrl/Cmd + D), чтобы создать семь ассетов Sword Data, по одному для каждого из мечей. Теперь переименуйте каждый ассет в соответствии с префабами:
Нажмите на первый ассет Sword Data в папке Sword Data и посмотрите на окно Inspector:
Здесь мы видим ассет, в котором будет храниться информация о конкретном мече. Заполните информацию для каждого меча. Постарайтесь дать им уникальное описание, стоимость в золоте и урон при атаке. В поле Icon Sprite используйте соответствующие спрайты, расположенные в папке Sword Icons:
Поздравляю! Вы создали Scriptable Object и настроили с помощью этого Scriptable Object несколько ассетов.
Использование Scriptable Object
Теперь мы приступим к получению данных из этих Scriptable Objects.
Во-первых, нам нужно добавить несколько публичных методов-получателей (getter methods), чтобы другие скрипты могли получать доступ к частным полям внутри Scriptable Object. Откроем SwordData.cs и допишем под добавленными ранее полями следующее:
Откроем Sword.cs и добавим следующий код:
Вот, что мы добавили этим кодом:
Нажмите на Play (Ctrl/Cmd + P) в редакторе Unity, а затем щёлкните самый левый меч:
В консоль должна выводиться информация, напоминающие данные, переданные из ассета Sword Data.
Scriptable Objects позволяют с лёгкостью заменять эти данные. Попробуйте вставлять разные Sword Data Scriptable Object в поле Sword Data меча.
Scriptable Objects на основе событий
Итак, мы создали Scriptable Object, и вы увидели, как можно получать доступ к его данным внутри игры. Но нам всё равно нужно интегрировать Sword Data с UI!
Для этого можно использовать быстрый и грязный паттерн Singleton. Однако мы теперь обладаем другими возможностями…
…а именно Scriptable Objects! Воспользуемся ими для создания чистого и аккуратно разделённого на части кода.
В этом разделе вы узнаете, как создавать Game Events с помощью класса UnityEvent.
Game Events и Listeners
В папке Scripts создайте два скрипта: GameEvent.cs и GameEventListener.cs. Они зависят друг от друга, поэтому чтобы избавиться от ошибок, нужно создать оба.
Вот что делает приведённый выше код:
В показанном выше коде происходит дальнейшее развитие проекта:
Подготовка редактора
Вернитесь в редактор Unity и создайте новую папку Game Events в Scripts >> ScriptableObjects. Затем создайте семь Game Events из Asset Menu, как мы это делали для каждого ассета Sword Data. Разместите их в новой папке Game Events.
Замените код внутри скрипта Sword.cs следующими строками:
Этот код добавляет в лавку торговца мечами две возможности:
Теперь у каждого меча есть ссылка на событие, вызываемое при нажатии на меч.
Интеграция с UI
Теперь нужно заставить работать UI. Наша цель заключается в отображении соответствующих данных Sword Data при нажатии на каждый меч.
Ссылки UI
Перед обновлением UI необходимо получить ссылку на каждый элемент UI. Начнём с создания нового скрипта под названием SwordMerchant.cs и добавления в этот новый скрипт следующего кода:
С помощью этого кода мы добавили следующее:
Слушатели и отклики UI
У всех мечей есть событие, на которое может подписаться UI с помощью скрипта GameEventListener. Добавьте GameEventListener для каждого события OnSwordSelected к GameObject SwordMerchantCanvas:
Как вы могли заметить, у нашего Game Event Listener есть два поля: событие Game Event, которое он слушает, и отклик, который вызывается при генерации Game Event.
В нашем случае отклик будет обновлять UI. Добавьте в скрипт SwordMerchant.cs следующий метод:
С помощью нашего нового метода мы можем добавить отклик к каждому GameEventListener.
Для каждого добавляемого отклика необходимо в качестве значения поля None (Object) ссылку на наш игровой объект SwordMerchantCanvas. После этого выберем SwordMerchant.UpdateDisplayUI из раскрывающегося меню справа от раскрывающегося списка Runtime Only.
Будьте внимательны и используйте правильный ассет Sword Data для каждого события OnSwordSelected.
Теперь мы можем запустить игру, нажать на меч и увидеть, что UI обновился соответствующим образом!
Поскольку мы используем Game Events, то можно просто SwordMerchantCanvas, и всё по-прежнему будет работать, только без UI. Это значит, что префабы мечей отделены от SwordMerchantCanvas.
Куда двигаться дальше?
Если вы что-то упустили в процессе рассказа, то можете скачать готовый проект, находящийся в материалах туториала.
Хотите больше узнать о Unity? Посмотрите нашу серию видео по Unity или прочитайте туториалы по Unity.