Как сделать пустой объект в unity

Добавил пользователь Skiper
Обновлено: 04.10.2024

Приветствую всех друзья! В прошлой статье я закончил обзор основного интерфейса Unity, подробно рассмотрев окно сцены. Сегодня мы поговорим о сценах и игровых объектах более подробно, так как это фундаментальные вещи, которые понадобятся для создания игры.

Unity дает возможность делать игры большому кругу людей заинтересованных в этом. Главной особенностью является то, что вам не нужны годы работы программистом или художником, чтобы начать делать небольшие и интересные игры. Существует несколько основных концепций рабочего процесса в Unity, которые необходимо понять. Однажды выучив и поняв их, вы будете делать игры в кратчайшие сроки. А то время что вы будете экономить – можно потратить на оттачивание и балансировку игры. Первые две концепции о которых я расскажу – это концепция сцены и игрового объекта.

Сцены.

Сцены содержат в себе меню и игровое окружение вашей игры. Они состоят из игровых объектов, о которых мы поговорим ниже. Думайте о каждой новой сцене как о новом уровне в своей игре. В каждой сцене вы размещаете окружение, украшения, препятствия, меню и прочее-прочее, по сути собирая свою игру по кусочкам (уровням).

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

Для того чтобы сохранить сцену необходимо либо в контекстном меню выбрать File/Save Scene , либо сочетанием клавиш Ctrl+S (Windows) и Cmd+S (Mac). Unity сохраняет ваши сцены как ассеты в папке Assets по умолчанию, но я рекомендую сделать внутри папки Assets отдельную папку для сцен и хранить их там. Это также значит, что ваши сцены вы можете увидеть в окне проекта, как и любой другой ресурс игры.

Открыть сцену можно двойным нажатием левой кнопки мыши в окне проекта по ранее сохраненному файлу сцены. Если при этом вы забыли сохранить текущую сцену – Unity спросит вас стоит ли это сделать перед ее закрытием.

Игровые объекты.

Игровой объект – это наиболее важная концепция в Unity. Любой объект в вашей игре будь то персонаж, свет, камера или визуальный эффект — это все игровые объекты. Но сам по себе игровой объект из себя ничего не представляет, ему нужно придать свойства чтобы он стал чем-то большим.

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

При создании игрового объекта на него автоматически вешается компонент Transform , это единственный компонент, который невозможно удалить с игрового объекта так как он представляет его в пространстве сцены. Любой другой компонент можно удалить или добавить на игровой объект по своему желанию.

Компоненты можно добавлять, удалять или изменять на игровом объекте. Для того чтобы добавить игровому объекту компонент, выберите его и нажмите на кнопку Add Component , в появившемся выпадающем меню выберите необходимый компонент и добавьте его. Чтобы удалить компонент с игрового объекта нажмите в окне инспектора на его название правой кнопкой мыши, появится контекстное меню, в котором необходимо выбрать пункт Remove Component .

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

Unity поддерживает работу с любыми 3D объектами созданными в стороннем программном обеспечении, но также она умеет сама создавать такие примитивные объекты как куб, сфера, капсула, цилиндр и плоскость. Эти объекты часто используются для быстрого прототипирования игр. Чтобы создать любой из них пройдите в контекстное меню GameObject/3D Objects и выберите любой из них. Тоже самое можно сделать в окне иерархии нажав на пустое место правой кнопкой мыши и выбрав пункт 3D Object .

Как я уже писал немного выше компонент Transform является единственным компонентом, который нельзя удалить с игрового объекта. Давайте посмотрим на его параметры немного более подробно:

1. Position – это позиция нашего игрового объекта в сцене в XYZ координатах

2. Rotation – это вращение нашего игрового объекта в сцене, оно также задается в XYZ, но это уже не координаты, а оси по которым мы поворачиваем наш объект в градусах.

3. Scale – это размер нашего игрового объекта в сцене. По умолчанию он равен 1. Меняется он также по всем 3 осям.

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

Чтобы добавить новый тег нужно выбрать в конце списка пункт Add Tag в открывшемся окне инспектора нажмите + и впишите свой тег. Теперь он есть в списке тегов. Также в Unity по умолчанию уже присутствует несколько тегов (например MainCamera, для определения главной камеры на сцене).

Если игровой объект статично стоит на сцене и никуда не перемещается – то это статический объект. Если же он движется во время выполнения игры – это динамический объект.

Когда вы помечаете игровой объект как статический (галочка напротив пункта Static ), при условии, что он не будет двигаться во время выполнения – такой объект будет экономить вычислительные мощности игрока, так как Unity автоматически оптимизирует работу с такими игровыми объектами.

Выпадающий список выше дает нам возможность выставить – какие предварительные вычисления будут применяться к этому игровому объекту. Включайте предварительные вычисления только для тех систем в которым наш игровой объект действительно нужно просчитать, иначе Unity будет в пустую тратить время на вычисления для того игрового объекта, которому это не нужно.

После работы со сценой и проектом в целом не забывайте сохранять изменения. В Unity сохранения делятся на 2 вида:

1. Это сохранение самой сцены

2. Это сохранение различных настроек проекта, а также ассетов и настроек в них

Как сохранить сцену я писал выше. А для сохранения проекта в любой момент выберите в контекстном меню File\Save Project . Также не забывайте – когда вы открыли префаб для редактирования – любое сохранение (как проекта, так и сцены) сохранит изменения в префабе.

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

🏓 Создаем 2D-игру на Unity: инструкция для новичка

Недавно мы рассказали о том, как научиться разработке игр на Unity . Продолжим тему на практике и покажем, как новичку создать на этой платформе первую 2D-игру.

Если вы хотите получить более систематическое образование в области разработки игр, мы рекомендуем рассмотреть факультет разработки игр онлайн-университета GeekBrains.

Двумерные игры сравнительно просты: для них не требуется сложных 3D-моделей, программный код по сравнению с 3D-проектами выглядит понятнее. Такие игры популярны как на десктопах, так и на мобильных устройствах. Unity также позволяет разрабатывать игры и для браузеров.

За последние годы вышло много популярных двумерных игр:

Программная реализация 2D-игр проще не только из-за отсутствия третьего измерения: на самой сцене меньше объектов, вместо трехмерных моделей плоские спрайты, вместо скелетной анимации – покадровая. А еще 2D-игры проще портировать на другие платформы – легче найти новую аудиторию.

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

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

Предполагаем, что вы уже установили редактор и создали аккаунт на портале Unity.

В первую очередь создадим новый проект и откроем его настройки (Edit → Project Settings). Во вкладке Editor установим параметр Default Behaviour Mode в значение 2D

Настройка проекта Детальная настройка проекта

Следующим шагом сохраним текущую активную сцену, назвав ее, например, Scene1. Теперь создадим основные игровые объекты: ракетку, мяч и менеджер игры, в котором будет храниться основная логика игры.

1. Создаем пустой объект, переименовываем в GameManager.

Создаем пустой объект

Создаем пустой объект

3. Создаем квадратный спрайт, называем его Pad (Assets → Create → Sprites → Square). Аналогично создаем круглый спрайт Ball (Assets → Create → Sprites → Circle). Масштабируем спрайт Pad со следующими параметрами – x:0.5, y:2.5, z:1.

Создаем спрайты

Создаем спрайты

4. Создаем префабы для Pad и Ball, после чего добавляем к ним компонент Box Collider 2D (включаем параметр Is Trigger) и компонент Rigidbody 2D (выставляем параметр Body Type в значение Kinematic).

Добавляем .компонент Box Collider 2D Настраиваем.компонент Box Collider 2D Добавляем компонент Rigidbody 2D Масштабируем спрайты

6. Заполняем скрипты следующим кодом.

GameManager.cs Ball.cs Pad.cs

6. Добавляем к префабу Ball и Pad теги с аналогичными именами. Выделив префабы, в инспекторе мы можем видеть выпадающий список тегов. Там же расположены и кнопки для добавления и редактирования тегов.

7. В настройках камеры выставляем параметр Projection в значение Orthographic, а параметр Clear Flag – в значение Solid Color.

Настройка камеры

Настройка камеры

8. Настраиваем кнопки, как показано на следующих скриншотах (Edit → Project Settings → Input Manager).

Настройка ввода, основное Настройка ввода, первый игрок Настройка ввода, второй игрок

Вот и всё, игра готова!

Пинг-понг, итоговый результат

Пинг-понг, итоговый результат

Билд для платформы Windows

1. Официальный туториал от Unity, где детально рассмотрен процесс создания roguelike RPG.

2. Youtube-канал Brackeys , где можно найти серию видеоуроков по созданию 2D-платформера.

3. Youtube-канал N3K EN содержит множество уроков как по отдельным компонентам Unity, так и полноценные серии уроков по созданию игр с нуля.

Если у вас мало опыта в разработке игр на Unity, мы рекомендуем обратить внимание на факультет разработки игр GeekBrains . Материал хорошо структурирован и содержит все необходимое для того, чтобы стать профессиональным Unity-разработчиком.

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

По окончании обучения вы будете иметь портфолио из 4 игр, которое можно показать на собеседовании. Если же какая-то часть материала будет непонятна, вы всегда можете обратиться к персональному преподавателю.

В данной статье я попытаюсь на простом примере разобраться в том, что такое ScriptableObject.

Я не являюсь экспертом и не претендую на истину в последней инстанции.

Настоятельно рекомендую всегда перепроверять данные, читая официальную документацию - для этого я и вставляю ссылки по ходу текста.

Если попытаться объяснить простыми словами, основной способ применения ScriptableObject - использование его в качестве контейнера данных (хотя никто не запрещает хранить в нём и методы), который можно переиспользовать независимо это экземпляров класса (и тут всё сразу стало понятно, ага).

Например, ScriptableObject может хранить набор свойств игровых объектов (разные предметы в РПГ, характеристики врагов и тд) - вы можете использовать его как шаблон, легко создавая новые предметы, попросту обновляя их характеристики через заданные вами поля.

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

Я создал три потрясающих спрайта, которые буду использовать здесь. Спасибо, Paint =)

Создадим папку Sprites и закинем в неё наши спрайты.

Перетянем одну из них в сцену и переименуем в Enemy. Создадим в иерархии новый объект и назовём его Label.

В объекте Label добавим компонент Text Mesh. Впишем в поле Text нужный нам текст, и сделаем его поменьше при помощи Character Size

Привяжем наш Label к объекту Enemy, простым перетаскиванием мышью, и расположим текст прямо над объектом.

Давайте теперь уберем наш спрайт, выбрав None в поле Sprite (мы могли изначально создать объект и без спрайта, но так немного нагляднее).

Для того, чтобы как то видеть наш объект, можно ткнуть на кубик рядом с названием объекта (Inspector, слева от чекбокса и имени объекта Enemy), и выбрать какую-нибудь иконку.

Создадим в ассетах папку Scripts, куда добавим новый скрипт с именем Enemy.

Отредактируем наш новый скрипт, сделав из него ScriptableObject.

using System.Collections; using System.Collections.Generic; using UnityEngine; /** * Данный атрибьют встривает создание нового объекта в меню assets/create * * fileName - имя файла, созданного из данного ScriptableObject. * Если оставить пустым, название будет взято по имени класса. * menuName - меню или подменю, в котором будет распологаться создание нашего объекта. * Если оставить пустым, то объект появится в основном меню. * order - порядок расположения в меню или подменю. **/ [CreateAssetMenu(fileName = "Enemy", menuName = "Configs/Enemy", order = 0)] public class Enemy : ScriptableObject < // Создаём приватные переменные для характеристик нашего объекта // Спрайт [SerializeField] Sprite sprite; // Имя [SerializeField] string name; /** * Для получения необходимых нам данных, лучше всего исполтзоввать систему геттеров/суттеров. * get - позволяет получить нужное нам свойство. * set - позволяет изменить нужное нам свойство. В данном примере задействовано не будет. **/ public Sprite enemySprite < get < return sprite; >> public string enemyName < get < return name; >> >

Если всё сделано правильно, то в меню assets/create должен появиться пункт Enemy.

Создадим в ассетах папку Configs, а в ней новый объект под именем BlueEnemyConfig.

Ткнём на него, и внесём данные - выберем синий спрайт (blue) и имя Dangerous Blue.

Для этого создадим скрипт EnemyBehaviour, привяжем его к объекту Enemy в иерархии, и отредактируем его.

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

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

Обработка ошибок очень важна, и сэкономит вам огромную кучу нервов и сил.

Подключим BlueEnemyConfig к игровому объекту Enemy.

Изменим цвет фона по-умолчанию для камеры на жёлтый, чтобы наш синий враг не потерялся.

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

Как вы видите, наш объект применил синий спрайт и надпись, что мы задали для BlueEnemyConfig.

Мы можем создавать одинаковые и разные объекты, применяя разные или одинаковые конфигурации.

Одно из самых частых и удобных методов применения ScriptableObject - работа с ранее созданными префабами. Например, создание волн врагов, конфигурация и/или расположение которых хранится в ScriptableObject.

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

Удалим наши объекты из иерархии (они уже сохранены в префабах), и создадим несколько новых, внутри общего объекта.

Расположим их случайным образом - именно на этих местах мы будем спаунить наших врагов.

Добавим их все в один объект под названием PointsContainer, и, сохранив его как префаб, удалим его с игрового поля.

Создадим новый ScriptableObject, который назовём Points.

Создадим новый конфиг EnemyWaveConfig, и загрузим в него наш префаб PointsContainer.

Создадим в иерархии новый объект EnemySpawner.

Создадим скрипт EnemySpawnerBehaviour и подключим к EnemySpawner.

Подключим наши префабы и конфиг с точками спауна врагов.

Благодаря тому, что мы всегда выбираем разные префабы ( enemyPrefabs[Random.Range(0, enemyPrefabs.Count)]), при каждом запуске мы будем видеть разный набор врагов.

Заметьте: все созданные враги подписаны, как имя + (clone).

ScriptableObject - очень крутая штука. Можно делать вложенные объекты-конфиги, можно переиспользовать их в разных объектах - все зависит от вашего скилла и воображения.

Хранить ли в ScriptableObject список предметов, настраивать волны врагов или устанавливать сложность игры - решать вам.

Надеюсь, информация выше оказалась кому-то полезной.

ScriptableObject это не контейнер данных, хотя это и одно из его основных применений. Будет ли он контейнером данных, если я создам в нем несколько методов и больше ничего, а затем использую в другом классе методы его экземпляра?)

Справка про ссылочные типы и значимые тоже не совсем к месту тут, т. к. В этом SO от монобеха ничем не отличается, как, впрочем, и от других классов.

Вообще, одна из ключевых особенностей SO в том, что его экземпляры можно в редакторе перетащить в параметры любого компонента, в котором есть поле такого типа. Что-то вроде Dependency Injection, но даже удобнее. В этом основной плюс, и важно понимать, что там могут быть не только данные, но и логика)

Вот у меня первая мысль была, когда только начал смотреть, что можно использовать SO для хранения различных методов-хелперов (конвертации всякого и прочее) и тд, чтобы их можно было легко переиспользовать где хочешь 😌
Немножко обновил описание, спасибо.

Просто по документации его основная роль - как раз контейнер данных.
Разработчики делают на это упор, но при этом детального разбора с примерами где он "reduce your Project’s memory" с тестами и тд пока не нашёл

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

Меня это удивляет очень сильно, если честно.
Unity - реально популярная штука, но с документацией прям какая то беда

ЗЫ интересно.
А если обновить изначальный код SO, подтянутся ли изменения в созданные из него экземпляры🤔 ?
Если нет, то использование его, как сервис с набором методов будет не очень удобно.
Не могу проверить, тк как нахожусь в рабочей поездке.

Если я правильно понял вопрос, то да, подтянутся)

А вообще, мой комментарий про методы скорее о том, что в SO можно задавать игровую логику, и вызывать её из монобехов. Так можно задавать в одно и то же поле монобеха разные SO одного типа (например, неследованные классы со своей логикой) и менять поведение объекта без нового кода. Можно создать несколько разных логик и отдать играться геймдизайнеру, который соберет из них нужную комбинацию. :)

Тоже интересное предложение
Плюсую, нужно больше эксперементировать )

Допустим у меня есть некая структура-список, которая содержит в себе ссылки на все scriptableObjects определённого вида. Unity выгрузит все объекты в оперативку устройства, как только я сошлюсь на этот список?
(в БД тебе прям всё-всё из списка грузить не надо, как я понимаю).

100% cказать не берусь, но насколько я помню - я читал на форуме, что Unity должна выгружать такие объекты только в том случае, если идёт прямое обращение в к ним (например, если тащишь из них какое то значение, или вызываешь метод).
Интересная идея для эксперимента, кстати.

Ещё, кстати, интересовало, является ли вот это нарушением MVC, когда у тебя отображение в виде спрайта мешается с моделью?

По-идее, да. Так как мы изменяем то, что на выходе получит юзер, напрямую.
Интересно было бы посмотреть, как пишут такие вещи в профессиональной среде.

Не обязательно это отображение, вполне данные. Но в целом, да, имеет смысл все элементы отображения держать близко, а не в данных, так проще художнику. Тот же префаб, например.
А если спрайт берётся динамически, например, подтягивается с сервера, то это уже без сомнения к модели относится.

Вы написали, что "благодаря этому мы можем уменьшить количество памяти. ". Не совсем понятно за счёт чего, если рассматривать ваш пример. Если речь идёт о метаданных объектов сцены, за счёт переноса части данных в scriptableobject, то это просто капля в море.
Возможно, на строках хорошо можно выехать. Но те же спрайты, на сколько я понимаю, будут и так оптимизированы для памяти за счёт атласов.
Интересно бы увидеть тесты.
Спасибо за статью

Не забывайте, что создание каждого нового игрового объекта - это уже поедание ресурсов.
Когда мы, например, генерируем врагов через ссылку на префаб - в памяти, по факту, не находятся несколько врагов.
Мы имеем один, много раз клонированный объект, те по факту -:один игровой объект.
Помимо его нахождения на игровом поле, garbage collector при уничтожении объекта попросту удалит используемую объектом ссылку, чем сэкономит какое-то количество ресурсов.
Я бы даже сказал, что они очень эффективны как раз в последнем пункте - при работе со сборщиком мусора.

Но это все - теория.

Тесты я бы и сам попросил, так как в одной статье вижу, где пишут за то, что SO помогают оптимизировать использование памяти, где-то наоборот.
Истина где-то там 😭

Зы. Спасибо за комментарий и прочтение.

". Когда мы, например, генерируем врагов через ссылку на префаб - в памяти, по факту, не находятся несколько врагов. "

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

Я не спорю, просто в документации разработчики делают упор именно на это: "Every time you instantiate that Prefab, it will get its own copy of that data. Instead of using the method, and storing duplicated data, you can use a ScriptableObject to store the data and then access it by reference from all of the Prefabs. This means that there is one copy of the data in memory.".
Вот реально бы найти полноценный разбор)

Так давно читал и вообще что-либо такое применял, что уже забыл.
В последнее время почуял, что начал покрываться мхом, так как на работе кодинг по-шаблону, все время одно и то же.
Огромное спасибо за ссылку - отличное чтиво.

Шаблоны они такие, постоянно вылетают из головы, пока не находится хорошие и запоминающиеся примеры из реальной жизни. Я и сам с удивлением обнаружил, что SO это Flyweight когда-то, а ведь тоже читал)

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

Мое первоначальное намерение состояло в том, чтобы создать объекты преобразования в массиве, потому что все, что мне нужно, - это определенные точки в пространстве, которые содержат информацию о позиции и вращении. Я обнаружил, что это невозможно, поэтому я решил создать массив пустых GameObjects :

Из этого я надеялся получить то, что мне нужно. Что это:

К сожалению, это невозможно, так как все center[i] равны нулю. Не создает ли new GameObject пустой объект GameObject с информацией о преобразовании?

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

4 ответа

Проверить на столкновение. Когда возникает желаемое столкновение, вы можете изменить прозрачность.

Вы заметите, что пример - это именно ваш вопрос.

Попробуйте этот метод расширения:

Затем вы можете вызвать его:

В Unity 5 лучший способ, который сработал для меня (СДЕЛАТЬ ОБЪЕКТ НЕВИДИМОМ), заключался в установке всех материалов игрового объекта, которые я хотел сделать невидимыми или прозрачными в режиме рендеринга. ЗАТЕМ нажмите маленькую круглую кнопку рядом с альбедо, а затем прокрутите список элементов вниз, пока не найдете тот, который называется UIMask. Выделите его и нажмите Enter. Я новичок, поэтому спросите, нужны ли вам дополнительные разъяснения.

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

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

Просто выполняется с помощью шейдеров, которые можно быстро и эффективно изменять во время выполнения

Читайте также: