У Unity всё плохо
На просторах интернета, и в частности хабра, очень трудно встретить статьи с критикой игрового движка Unity. Я решил это исправить, и приготовил вам текст о переходе на DOTS, насилию над C#, знаменитых UI пакетах, MonoBehaviour, универсальности и о многом другом.
Статья не требует от вас знаний о создании игр на Unity, я ее писал с учетом того, что ее будет читать обычный программист, который сравнивает плюсы и минусы разных движков, чтоб выбрать подходящий для своего проекта. В конце концов, может вам будет просто интересно узнать, что же это за движок такой, для которого курсы рекламируются на каждом шагу.
DOTS
В данный момент Unity активно переходит на новый стек технологий под названием DOTS. Транзит сопровождается лозунгом «Производительность по умолчанию» и идеей того, что С# может быть таким же быстрым как C++ у UnrealEngine и других движков. Главные фронтмены данного действа это Entities, Jobs и Burst.
Теория
Если вы уже знаете, что из себя представляет пакет DOTS, тогда можете смело переходить к пункту Имплементация.
Entities представляет из себя реализацию популярного в игровой индустрии паттерна ECS. ECS это паттерн, где код делится на сущности к которым добавляются компоненты с данными, состоянием компонентов у сущностей управляют системы, которые эффективно перебирают сущности с нужными им компонентами и изменяют данные компонентов по надобности.
К примеру, у вас игра — шутер, в которой снаряд это сущность с компонентом Bullet в котором хранятся данные о расположении снаряда. Есть система движения снарядов, которая перебирает все сущности с компонентом Bullet и двигает их вперед, а есть система рендера снарядов, которая перебирает все сущности со снарядом Bullet и рендерит их.
Реализаций ECS есть великое множество, но в основном, используют следующие способы оптимизации перебора сущностей:
- Хранение компонентов эффективно в памяти в соответствии с архетипом существа к которому они привязаны. Архетип это уникальное сочетание компонентов у существа. В случае Unity, компоненты хранятся в чанках по 16кб в соответствии с архетипом. Выходит, что чанки с компонентами хранятся друг за другом в памяти.
- Распараллеливание обработки существ системой. Тут всё очевидно, двигать 50 тысяч снарядов в каком-то шутере быстрее в 32х потоках одновременно. От программиста не требуется особых телодвижений для управления многопоточностью, потенциально ECS может эффективно управлять потоками самостоятельно. В Unity роль управления потоками делегирована фреймворку Jobs.
Такой паттерн хорошо подходит сложным играм, в которых есть очень много сущностей которые надо очень часто перебирать (к примеру ММО). Вдобавок, ECS управляет зависимостями, позволяя игре становиться все больше и больше без последствий.Но есть и обратная сторона медали, ECS плохо подходит играм, в которых мало сущностей и их не надо часто перебирать (например 99% мобильного рынка).
Jobs это реализация безопасной мультипоточности путем создания экземпляра «работы». Работу можно запланировать, получить ее обработчик и выполнить ее. Также работу можно запланировать после другой работы, или вместе с другими работами. Таким образом создаются целые цепи последовательных задач. Сами задачи выполняются сразу в нескольких потоках. Например, вам надо умножить все числа массива А с вместительностью в 100 элементов и положить их в массив B. Это можно сделать в десяти потоках, в каждом из них задача будет обрабатывать по 10 элементов.
Burst это компилятор, который транслирует IL байткод в оптимизированный нативный код с помощью LLVM. В основном, используется для компиляции работ с Jobs.
Имплементация
Теперь, когда вы понимаете что из себя представляет новый стек технологий теоретически, можно поговорить об имплементации. А она, как всегда, не выдержала столкновения с реальностью.
Начнем с того, как же команда Unity хочет сделать C# таким же быстрым, как C++, а именно:
- Создали новый компилятор для Работ с векторизацией и intrinsics (разве что без блекджека).
- Создали нессылочные альтернативы массиву, списку, очереди и т.д которые дружат с Burst’ом. Особенность в том, что эти контейнеры надо аллоцировать и после их жизненного цикла освобождать, иначе утечка. Причем, аллоцировать надо не абы как, а с правильными лейблами (Persistent/Temp/TempJob).
- Ввели в использование указатели на списки и указатели на функции. Также вам может понадобиться использовать Malloc, MemMove, MemCpy и подобные
brand-newфункции.
Я думаю, вы уже поняли к чему я клоню. Они решили, что лучший способ сделать сишарп таким же быстрым как и плюсы, это сделать из сишарпа плюсы! *занавес, бурные овации, публика в шоке*
Ладно указатели, ладно Dispose у контейнеров, но когда вы начали писать новый компилятор для языка, можно же было что-то заподозрить! Пытаться уже третий год реализовать стек технологий на языке, который не подходит вашему стеку, и при этом переделывать* язык, это же сумасшествие!
Ещё один пример несовместимости DOTS и C# это Jobs с Работой IJobChunk и производными. Для того, чтобы проитерировать 3 компонента c помощью IJobChunk, вам надо 43 строки кода. Ситуацию могли бы спасти макросы, но они в C# предательски отсутствуют!
Следующая проблема нового стека Unity это недостаток многих функций, которые, иногда, могут вам пригодиться в создании игры, например:
- Звук. Версия пакета для звука 0.1.0-preview17 и за 3 года он так и не обновлялся.
- Интерфейс. Тут всё проще, пакета для интерфейса с поддержкой Entities просто нет.
- 2д. Существует com.unity.2d.entities, но он создан для Project Tiny и работает в общем-то только с ним, о Project Tiny тоже позже.
- Анимации. Пакет тоже существует, версия 0.9.0-preview.6, в теории использование возможно, на практике не очень.
- Всё элементы движка, которые не требуют очевидного отдельного пакета. Свет, камера, партиклы и т.д, всеми ими нельзя управлять через Entities, что угодно делайте. Можете создавать псевдо-сущность с компонентом, к примеру, камеры, и отдельной системой в главном потоке синхронизировать поля между MonoBehaviour камерой и вашей псевдо-камерой, можете другие костыли городить. За 3 года решения от Unity так и нет.
*под переделыванием языка я подразумеваю минимизирование использования ссылочных объектов и, как следствие, кучи путем создания кастомных аллокаторов, компиляторов которые не поддерживают кучу и т.п.
Проблемы
Предположим, что отсутствующие пакеты можно дописать, а текущую имплементацию можно ещё починить (в конце концов, можно переписать Roslyn!). Но проблемы самой DOTS как концепции, быстро решить не выйдет.
DOTS по умолчанию сложен. ECS требует полного понимания, как он работает, программисту надо знать на что влияет Read/Write доступ к компонентам, что такое Sync point и как сократить их количество, зачем нужен ECB, WriteGroup, гибридные компоненты и многое, многое другое. Также есть Jobs со своими контейнерами на указателях и такой же морокой с Read/Write доступом, Burst с миллиардом приспособлений для оптимизиации и примерами в документации из ассемблера.
Такая сложность явно не идёт на руку движку, одна из основных преимуществ которого простота. Unity занял свое место на рынке как «движок для дизайнеров, а не программистов», на нём делают Cuphead, Ori, Hollow Knight и другие игры которые не Factorio по сложности исполнения и требуемой оптимизации. У Unity занят рынок мобильных игр, маленьких кросс-платформенных инди игр, игр уровня «мы с парнями другие движки не знали, пришлось на этом пилить» (таким образом получаются Rust и Tarkov), в общем, идиллия. ААА игры не будут делать на Unity даже с полностью реализованным DOTS, ведь для них уже пишут отдельные движки на основе опенсоурса (UE) или вообще с нуля, а сложные инди игры делают энтузиасты на своих микро-движках, фреймворках или на том же UE.
В общем, плюсы от перехода на DOTS неочевидны, а минусы из-за нехватки ресурсов компании на поддержку и развития старых решений из уже уходящей эры MonoBehaviour присутствуют.
Project Tiny
В дополнение к выше написанному, хочу упомянуть Project Tiny. Это этакий набор мини-фреймворков для DOTS, которые должны помочь в разработке «Instant games» или, если выражаться русским языком, сделанные за 2 недели Егором из 9Б гипер казуальные игры типа тривряд. Также для Project Tiny команда Unity написала новую среду выполнения DOTS Runtime, вот вам документация (кстати в гугл доках, такого я не видел). Опять пересказывать то, что они пытаются переделать C#, смысла я не вижу, просто обозначу, что факт существования данного набора пакетов подтверждает то, что они хотят именно переделать движок с новым стеком DOTS, что в свою очередь, делает проблемы, описанные выше, ещё более значимыми.
Unity, но без DOTS
Под данным заголовком я хочу описать проблемы как старого архитектурного решения Unity, так и самого Unity как движка.
MonoBehaviour
Начнем с основного старого архитектурного решения — MonoBehaviour. Mono потому что на C#, раньше ещё был, к примеру, JSBehaviour, но все языки кроме C# в Unity бесславно умерли, так и остался один единственный MonoBehaviour.
Если кратко излагаться, MonoBehaviour представляет из себя базовый класс для скриптов в Unity, унаследованные от него классы можно добавить на любой объект в сцене как компоненты, а публичные поля таких классов красивенько отображаются в редакторе. Код пишется в методах со спец. именем, которые ядро движка на С++ вызывает самостоятельно, такие методы называются Messages, их у MonoBehaviour целая куча, от обычных Start и Update до OnCollisionEnter и OnApplicationQuit .
Такое решение довольно простое в понимании и не требует вообще никаких навыков у программиста, у вас все под рукой. Для больших проектов это, естественно, никуда не годится. Тут нет какой-то внятной архитектуры, у вас логика приложения находится сразу же в структуре с данными (компоненте). MonoBehaviour почти не предоставляет никаких абстракций, не дает инструмента для управления зависимостями, методы для поиска объектов с MonoBehvaiour на сцене де факто антипаттерн из-за производительности, методы для вызова Message-методов у других MonoBehaviour ещё больше антипаттерн из-за ещё худшей производительности.
В принципе создание чего-то сложнее тривряд с активным использованием MonoBehaviour не рекомендуется, а поскольку модульность в старом Unity отсутствует как понятие, просто убрать пакет с MonoBehaviour и написать что-то свое вы, конечно, не можете. Так и живут разработчики под Unity с гайдлайнами по оптимизации, в которых рекомендуют не использовать половину функций движка.
Команда Unity давным давно забила на попытки хоть как-то развить эту систему и пофиксить проблемы с производительностью.
Editor и UI
Разработчики Unity не умеют в UI. За 16 лет они не смогли создать пакет для адекватного интерфейса с xml/css/js и имплементировать редактор своего движка на нем. Для игр они сделали какой-то хлам с Canvas-ом и перетаскиванием панелей по иерархии сцены, а для редактора они предоставили что-то невообразимо ужасное с IMGUI на C# и рефлексией.
Спустя 16 лет они поняли, что шутки про использование штатного пакета для интерфейса Unity на форумах больше не смешные, и решили сделать новый пакет для интерфейса — UIElements (UIToolkit), с xml и css, но без js. Новый пакет для интерфейса непригоден для работы из-за отсутствия функционала у стилей. В нем нет анимаций, нет масок, нет полей для настроек выставления фона (только background-color и background-image), нет настроек шрифта и теней. Можете сравнить набор свойств у обычного CSS, и USS Unity.
Можно было бы сказать, что реализовать полный набор функций CSS движка довольно сложно, но вот Valve создали свой фреймворк Panorama с JS’ом, анимациями, масками, фоном, партиклами, сценами и многим другим. Благодаря ему, у игр Valve одни из самых лучших интерфейсов в индустрии. Понятно, что сравнивать Valve с Unity не совсем корректно, но это пример успешной реализации xml/css/js интерфейса в движке.
Декларируемая универсальность
Уже не совсем техническая, но огромная проблема Unity прошлого, настоящего и будущего. Unity старается быть универсальным, но игровой движок по природе своей не может быть универсальным. Нельзя сделать движок, который одинаково подходил бы сандбокс игре с процедурной генерацией мира, кооперативному FPS шутеру и мобильному кликеру. У разных игр разные требования к архитектуре движка, и если ваш движок это не каркас для плагинов как vim, то сделать его одинаково подходящим для всех не выйдет.
В случае с Unity это выливается в то, что ни одно отдельно взятое общее решение движка просто не подходит вашей конкретной проблеме. Как итог, вы постепенно отказываетесь от предоставленных движком решений и пишете свои, от чего попросту теряете время.
Этой проблеме, по сравнению с остальными, выделено не так много места в статье, но она фундаментальна. Именно эта проблема, скорее всего, потратит тонну вашего времени и похоронит проект, или уже похоронила. Если разработчики Unity сразу бы решили, для каких игр они делают свой движок, этой статьи бы не было.
Другое
Руководствуясь больше долгом о написании всех недочетов Unity, чем здравым смыслом, хочу отметить ещё немного мелких проблем которые не заслуживают отдельного параграфа, но заслуживают упоминание:
- Стилистика кода у биндингов Unity с префиксами m_ , чрезмерным использованием internal и бесполезными комментариями наподобие «x — Left coordinate, y — Top coordinate». Пример.
- Существование авто-сериалайзера Unity который работает хуже чем любой другой из существующих в мире, я думаю что сериалайзер на конвейерах в Factorio работал бы лучше, и как минимум, поддерживал бы сериализацию словаря.
- Перезагрузка всех ресурсов с надписью «Hold on» после каждой правки кода. Команда Unity клянется что ничего не могут с этим сделать, но это нетерпимо.
В Unity до сих пор нет поддержки C# 9, я просто напомню, что последняя версия уже C# 10.Поддержку #9 давно добавили.- Асинхронные юнит тесты обещали, но конечно, не сделали. Приходиться создавать костыли.
Конец
Статья вышла немного больше, чем я думал и наверняка я где-то допустил ошибку, так что прошу в комментарии. А если вы тот самый человек из начала статьи, который ищет движок для своего проекта, можете ознакомиться со следующим списком:
Для небольших игр с простой 3д или 2д графикой
- Unity. Не смотря на все минусы перечисленные выше, скорее всего для простых игр он вам подойдет.
- Godot. Сам не пробовал, по ощущениям Unity v2, но опенсоурс и не будет требовать от вас деньги и ставить свой логотип в начале.
- GameMaker: Studio. Создан для 2д игр, на нем сделали Undertale. Без подписки минимум за 10$ делать ничего не хочет.
- Microsoft XNA. Не движок, но фреймворк для создания игр на C#, больше не поддерживается (но есть форки). На нем создают довольно много разных инди игр и по сей день, одна из самых популярных это Stardew Valley.
Для средних или больших игр с 3д графикой
- UnrealEngine. Больше мне советовать нечего, скорее всего он вам подойдет. Писать код на C++ это сжигание тонны времени, но блюпринты могут вас спасти.
Другое
Amethyst. Движок на Rust, пока без своего редактора, естественно опенсоурс.Разработка движка прекращена.- Bevy. Конкурент предыдущего движка, можете попробовать оба.
MonoBehaviour
Благодарим вас за то, что вы помогаете нам улучшить качество документации по Unity. Однако, мы не можем принять любой перевод. Мы проверяем каждый предложенный вами вариант перевода и принимаем его только если он соответствует оригиналу.
Ошибка внесения изменений
По определённым причинам предложенный вами перевод не может быть принят. Пожалуйста попробуйте снова через пару минут. И выражаем вам свою благодарность за то, что вы уделяете время, чтобы улучшить документацию по Unity.
Ваше имя Адрес вашей электронной почты Предложение * Разместить предложенное
Описание
MonoBehaviour это базовый класс, от которого наследуются все скрипты.
При использовании Javascript каждый скрипт автоматически наследуется от MonoBehaviour. Когда используется C# или Boo Вам необходимо явно наследоваться от MonoBehaviour.
Примечание: Флажок выключающий MonoBehavior (в редакторе) будет только предотвращать выполнение функций Start(), Awake(), Update(), FixedUpdate(), и OnGUI(). Если ни одной из этих функций в скрипте не присутствует — флажок не отображается.
Переменные
useGUILayout | Disabling this lets you skip the GUI layout phase. |
Открытые функции
CancelInvoke | Отменяет все вызовы Invoke в этом MonoBehaviour. |
Invoke | Вызывает метод methodName по истечении времени time секунд. |
InvokeRepeating | Вызывает метод methodName по истечении времени time секунд, затем повторяет вызов каждые repeatRate секунд. |
IsInvoking | Есть ли какой то ожидающий вызов methodName? |
StartCoroutine | Запуск корутины. |
StopAllCoroutines | Останавливает все корутины запущенные на этом MonoBehaviour. |
StopCoroutine | Останавливает все корутины с именем methodName запущенные на этом MonoBehaviour. |
Статические функции
Logs message to the Unity Console (identical to Debug.Log). |
Сообщения
Awake | Функция Awake вызывается когда экземпляр скрипта будет загружен. |
FixedUpdate | Эта функция вызывается с частотой фиксированных кадров (fixed framerate), если MonoBehaviour включен. |
LateUpdate | LateUpdate вызывается каждый кадр, если Behaviour включен. |
OnAnimatorIK | Обратный вызов (Callback) для установки IK анимации (инверсной кинематики). |
OnAnimatorMove | Обратный вызов для обработки перемещения анимации для модификации смещения корня. |
OnApplicationFocus | Посылается ко всем игровым объектам когда плейер получает или теряет фокус. |
OnApplicationPause | Посылается ко всем игровым объектам когда плейер на паузе. |
OnApplicationQuit | Sent to all game objects before the application is quit. |
OnAudioFilterRead | If OnAudioFilterRead is implemented, Unity will insert a custom filter into the audio DSP chain. |
OnBecameInvisible | OnBecameInvisible is called when the renderer is no longer visible by any camera. |
OnBecameVisible | OnBecameVisible is called when the renderer became visible by any camera. |
OnCollisionEnter | OnCollisionEnter вызывается, когда этот collider/rigidbody начал соприкосновение с другим rigidbody/collider. |
OnCollisionEnter2D | Передается когда входящий коллайдер контактирует с коллайдером данного объекта (только 2D физика). |
OnCollisionExit | OnCollisionExit вызывается, когда collider/rigidbody прекращает контакт с другим rigidbody/collider. |
OnCollisionExit2D | Передается, когда коллайдер другого объекта перестает соприкасаться с коллайдером этого объекта (только 2D физика). |
OnCollisionStay | OnCollisionStay вызывается один раз в кадр для каждого collider/rigidbody, который касается другого rigidbody/collider. |
OnCollisionStay2D | Передается каждый кадр, пока коллайдер другого объекта контактирует с коллайдером данного объекта (только 2D физика). |
OnConnectedToServer | Called on the client when you have successfully connected to a server. |
OnControllerColliderHit | OnControllerColliderHit вызывается тогда, когда контроллер сталкивается с коллайдеров, во время выполнения метода Move. |
OnDestroy | This function is called when the MonoBehaviour will be destroyed. |
OnDisable | This function is called when the behaviour becomes disabled () or inactive. |
OnDisconnectedFromServer | Called on the client when the connection was lost or you disconnected from the server. |
OnDrawGizmos | Implement OnDrawGizmos if you want to draw gizmos that are also pickable and always drawn. |
OnDrawGizmosSelected | Implement this OnDrawGizmosSelected if you want to draw gizmos only if the object is selected. |
OnEnable | This function is called when the object becomes enabled and active. |
OnFailedToConnect | Called on the client when a connection attempt fails for some reason. |
OnFailedToConnectToMasterServer | Called on clients or servers when there is a problem connecting to the MasterServer. |
OnGUI | OnGUI is called for rendering and handling GUI events. |
OnJointBreak | Вызывается при разрушении сустава, прикрепленного к такому же игровому объекту. |
OnJointBreak2D | Вызывается при разрушении сустава, прикрепленного к такому же игровому объекту. |
OnLevelWasLoaded | This function is called after a new level was loaded. |
OnMasterServerEvent | Called on clients or servers when reporting events from the MasterServer. |
OnMouseDown | OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider. |
OnMouseDrag | OnMouseDrag is called when the user has clicked on a GUIElement or Collider and is still holding down the mouse. |
OnMouseEnter | Called when the mouse enters the GUIElement or Collider. |
OnMouseExit | Called when the mouse is not any longer over the GUIElement or Collider. |
OnMouseOver | Called every frame while the mouse is over the GUIElement or Collider. |
OnMouseUp | OnMouseUp is called when the user has released the mouse button. |
OnMouseUpAsButton | OnMouseUpAsButton is only called when the mouse is released over the same GUIElement or Collider as it was pressed. |
OnNetworkInstantiate | Called on objects which have been network instantiated with Network.Instantiate. |
OnParticleCollision | OnParticleCollision is called when a particle hits a collider. |
OnPlayerConnected | Called on the server whenever a new player has successfully connected. |
OnPlayerDisconnected | Called on the server whenever a player disconnected from the server. |
OnPostRender | OnPostRender is called after a camera finished rendering the scene. |
OnPreCull | OnPreCull вызывается до того, как камера отсечёт сцену. |
OnPreRender | OnPreRender вызывается перед тем, как камера начнёт рендерить сцену. |
OnRenderImage | OnRenderImage вызывается после того как весь рендеринг для отрисовки изображения завершиться. |
OnRenderObject | OnRenderObject вызывается после того, как камера отрендерила сцену. |
OnSerializeNetworkView | Used to customize synchronization of variables in a script watched by a network view. |
OnServerInitialized | Called on the server whenever a Network.InitializeServer was invoked and has completed. |
OnTransformChildrenChanged | This function is called when the list of children of the transform of the GameObject has changed. |
OnTransformParentChanged | This function is called when the parent property of the transform of the GameObject has changed. |
OnTriggerEnter | OnTriggerEnter вызывается, когда Collider other входит в триггер. |
OnTriggerEnter2D | Передается, когда другой обьект входит в триггер присоединенный к данному обьекту (только 2D физика). |
OnTriggerExit | OnTriggerExit вызывается, когда Collider other перестает соприкасаться с триггером. |
OnTriggerExit2D | Передается когда другой объект покидает триггер, присоединенный к данному объекту(только 2D физика). |
OnTriggerStay | OnTriggerStay is called once per frame for every Collider other that is touching the trigger. |
OnTriggerStay2D | Передается каждый кадр, пока другой объект находится в триггере, присоединенном к этому объекту (только 2D физика). |
OnValidate | Эта функция вызывается когда скрипт загружается или изменяется значение в Инспекторе (Вызывается только в редакторе). |
OnWillRenderObject | OnWillRenderObject вызвается один раз для каждой камеры, если объект в зоне видимости. |
Reset | Reset to default values. |
Start | Start is called on the frame when a script is enabled just before any of the Update methods is called the first time. |
Update | Update вызывается каждый кадр, если MonoBehaviour включен. |
Унаследованные члены
Переменные
enabled | Enabled Behaviours are Updated, disabled Behaviours are not. |
isActiveAndEnabled | Has the Behaviour had enabled called. |
gameObject | The game object this component is attached to. A component is always attached to a game object. |
tag | Тег данного игрового объекта. |
transform | The Transform attached to this GameObject (null if there is none attached). |
hideFlags | Should the object be hidden, saved with the scene or modifiable by the user? |
name | The name of the object. |
Открытые функции
BroadcastMessage | Вызывает метод названный methodName на каждом MonoBehaviour этого game object-а или любого из его потомков. |
CompareTag | Помечен ли этот игровой объект тэгом tag? |
GetComponent | Возвращает компонент типа type, если он прикреплен к игровому объекту и null, если не прикреплен. |
GetComponentInChildren | Returns the component of Type type in the GameObject or any of its children using depth first search. |
GetComponentInParent | Returns the component of Type type in the GameObject or any of its parents. |
GetComponents | Returns all components of Type type in the GameObject. |
GetComponentsInChildren | Returns all components of Type type in the GameObject or any of its children. |
GetComponentsInParent | Returns all components of Type type in the GameObject or any of its parents. |
SendMessage | Вызывает метод с именем methodName в каждом MonoBehaviour на этом объекте. |
SendMessageUpwards | Вызывает на каждом MonoBehaviour в данном игровом объекте и на каждом предке скрипта метод с именем methodName. |
GetInstanceID | Returns the instance id of the object. |
ToString | Returns the name of the game object. |
Статические функции
Destroy | Removes a gameobject, component or asset. |
DestroyImmediate | Destroys the object obj immediately. You are strongly recommended to use Destroy instead. |
DontDestroyOnLoad | Makes the object target not be destroyed automatically when loading a new scene. |
FindObjectOfType | Returns the first active loaded object of Type type. |
FindObjectsOfType | Returns a list of all active loaded objects of Type type. |
Instantiate | Returns a copy of the object original. |
Операторы
bool | Does the object exist? |
operator != | Compares if two objects refer to a different object. |
operator == | Compares two object references to see if they refer to the same object. |
MonoBehaviour
MonoBehaviour is the base class from which every Unity script derives.
When you use C#, you must explicitly derive from MonoBehaviour.
This class doesn’t support the null-conditional operator (?.) and the null-coalescing operator (??).
For code samples, see the individual MonoBehaviour methods.
Note: There is a checkbox for enabling or disabling MonoBehaviour in the Unity Editor. It disables functions when unticked. If none of these functions are present in the script, the Unity Editor does not display the checkbox. The functions are:
See Also: The Deactivating GameObjects page in the manual.
Variables
runInEditMode | Allow a specific instance of a MonoBehaviour to run in edit mode (only available in the editor). |
useGUILayout | Disabling this lets you skip the GUI layout phase. |
Public Functions
CancelInvoke | Отменяет все вызовы Invoke в этом MonoBehaviour. |
Invoke | Вызывает метод methodName по истечении времени time секунд. |
InvokeRepeating | Вызывает метод methodName по истечении времени time секунд, затем повторяет вызов каждые repeatRate секунд. |
IsInvoking | Есть ли какой то ожидающий вызов methodName? |
StartCoroutine | Starts a Coroutine. |
StopAllCoroutines | Останавливает все корутины запущенные на этом MonoBehaviour. |
StopCoroutine | Останавливает все корутины с именем methodName запущенные на этом MonoBehaviour. |
Static Functions
Logs message to the Unity Console (identical to Debug.Log). |
Messages
Awake | Функция Awake вызывается когда экземпляр скрипта будет загружен. |
FixedUpdate | Frame-rate independent MonoBehaviour.FixedUpdate message for physics calculations. |
LateUpdate | LateUpdate вызывается каждый кадр, если Behaviour включен. |
OnAnimatorIK | Обратный вызов (Callback) для установки IK анимации (инверсной кинематики). |
OnAnimatorMove | Обратный вызов для обработки перемещения анимации для модификации смещения корня. |
OnApplicationFocus | Посылается ко всем игровым объектам когда плейер получает или теряет фокус. |
OnApplicationPause | Посылается ко всем игровым объектам когда плейер на паузе. |
OnApplicationQuit | Sent to all GameObjects before the application quits. |
OnAudioFilterRead | If OnAudioFilterRead is implemented, Unity will insert a custom filter into the audio DSP chain. |
OnBecameInvisible | OnBecameInvisible is called when the renderer is no longer visible by any camera. |
OnBecameVisible | OnBecameVisible is called when the renderer became visible by any camera. |
OnCollisionEnter | OnCollisionEnter вызывается, когда этот collider/rigidbody начал соприкосновение с другим rigidbody/collider. |
OnCollisionEnter2D | Передается когда входящий коллайдер контактирует с коллайдером данного объекта (только 2D физика). |
OnCollisionExit | OnCollisionExit вызывается, когда collider/rigidbody прекращает контакт с другим rigidbody/collider. |
OnCollisionExit2D | Передается, когда коллайдер другого объекта перестает соприкасаться с коллайдером этого объекта (только 2D физика). |
OnCollisionStay | :ref::OnCollisionStay is called once per frame for every collider/rigidbody that is touching rigidbody/collider. |
OnCollisionStay2D | Передается каждый кадр, пока коллайдер другого объекта контактирует с коллайдером данного объекта (только 2D физика). |
OnConnectedToServer | Called on the client when you have successfully connected to a server. |
OnControllerColliderHit | OnControllerColliderHit вызывается тогда, когда контроллер сталкивается с коллайдеров, во время выполнения метода Move. |
OnDestroy | Destroying the attached Behaviour will result in the game or Scene receiving OnDestroy. |
OnDisable | This function is called when the behaviour becomes disabled. |
OnDisconnectedFromServer | Called on the client when the connection was lost or you disconnected from the server. |
OnDrawGizmos | Implement OnDrawGizmos if you want to draw gizmos that are also pickable and always drawn. |
OnDrawGizmosSelected | Implement OnDrawGizmosSelected to draw a gizmo if the object is selected. |
OnEnable | This function is called when the object becomes enabled and active. |
OnFailedToConnect | Called on the client when a connection attempt fails for some reason. |
OnFailedToConnectToMasterServer | Called on clients or servers when there is a problem connecting to the MasterServer. |
OnGUI | OnGUI is called for rendering and handling GUI events. |
OnJointBreak | Вызывается при разрушении сустава, прикрепленного к такому же игровому объекту. |
OnJointBreak2D | Called when a Joint2D attached to the same game object breaks. |
OnMasterServerEvent | Called on clients or servers when reporting events from the MasterServer. |
OnMouseDown | OnMouseDown is called when the user has pressed the mouse button while over the Collider. |
OnMouseDrag | OnMouseDrag is called when the user has clicked on a Collider and is still holding down the mouse. |
OnMouseEnter | Called when the mouse enters the Collider. |
OnMouseExit | Called when the mouse is not any longer over the Collider. |
OnMouseOver | Called every frame while the mouse is over the Collider. |
OnMouseUp | OnMouseUp is called when the user has released the mouse button. |
OnMouseUpAsButton | OnMouseUpAsButton is only called when the mouse is released over the same Collider as it was pressed. |
OnNetworkInstantiate | Called on objects which have been network instantiated with Network.Instantiate. |
OnParticleCollision | OnControllerColliderHit вызывается тогда, когда контроллер сталкивается с коллайдеров, во время выполнения метода Move. |
OnParticleSystemStopped | OnParticleSystemStopped is called when all particles in the system have died, and no new particles will be born. New particles cease to be created either after Stop is called, or when the duration property of a non-looping system has been exceeded. |
OnParticleTrigger | OnParticleTrigger is called when any particles in a Particle System meet the conditions in the trigger module. |
OnParticleUpdateJobScheduled | OnParticleUpdateJobScheduled is called when a Particle System’s built-in update job has been scheduled. |
OnPlayerConnected | Called on the server whenever a new player has successfully connected. |
OnPlayerDisconnected | Called on the server whenever a player disconnected from the server. |
OnPostRender | OnPostRender is called after a camera finished rendering the Scene. |
OnPreCull | OnPreCull is called before a camera culls the Scene. |
OnPreRender | OnPreRender is called before a camera starts rendering the Scene. |
OnRenderImage | OnRenderImage вызывается после того как весь рендеринг для отрисовки изображения завершиться. |
OnRenderObject | OnRenderObject is called after camera has rendered the Scene. |
OnSerializeNetworkView | Used to customize synchronization of variables in a script watched by a network view. |
OnServerInitialized | Called on the server whenever a Network.InitializeServer was invoked and has completed. |
OnTransformChildrenChanged | This function is called when the list of children of the transform of the GameObject has changed. |
OnTransformParentChanged | This function is called when the parent property of the transform of the GameObject has changed. |
OnTriggerEnter | When a GameObject collides with another GameObject, Unity calls OnTriggerEnter. |
OnTriggerEnter2D | Передается, когда другой обьект входит в триггер присоединенный к данному обьекту (только 2D физика). |
OnTriggerExit | OnTriggerExit вызывается, когда Collider other перестает соприкасаться с триггером. |
OnTriggerExit2D | Передается когда другой объект покидает триггер, присоединенный к данному объекту(только 2D физика). |
OnTriggerStay | OnTriggerStay is called once per physics update for every Collider other that is touching the trigger. |
OnTriggerStay2D | Передается каждый кадр, пока другой объект находится в триггере, присоединенном к этому объекту (только 2D физика). |
OnValidate | This function is called when the script is loaded or a value is changed in the Inspector (Called in the editor only). |
OnWillRenderObject | OnWillRenderObject is called for each camera if the object is visible and not a UI element. |
Reset | Reset to default values. |
Start | Start is called on the frame when a script is enabled just before any of the Update methods are called the first time. |
Update | Update вызывается каждый кадр, если MonoBehaviour включен. |
Inherited members
Variables
enabled | Включенное Поведение обновляется, выключенное Поведение не обновляется. |
isActiveAndEnabled | Has the Behaviour had active and enabled called? |
gameObject | Игровой объект к которому прикреплён данный компонент. Компонент всегда прикреплён к игровому объекту. |
tag | Тег данного игрового объекта. |
transform | The Transform attached to this GameObject. |
hideFlags | Should the object be hidden, saved with the Scene or modifiable by the user? |
name | The name of the object. |
Public Functions
BroadcastMessage | Вызывает метод названный methodName на каждом MonoBehaviour этого game object-а или любого из его потомков. |
CompareTag | Помечен ли данный игровой объект тегом tag? |
GetComponent | Returns the component of Type type if the GameObject has one attached, null if it doesn’t. Will also return disabled components. |
GetComponentInChildren | Возвращает компонент типа type в GameObject или некоторого его потомка через поиск в глубину. |
GetComponentInParent | Возвращает все компоненты типа type из GameObject’а или из любого его родителя. |
GetComponents | Возвращает все компоненты типа type в GameObject. |
GetComponentsInChildren | Возвращает все компоненты типа type в GameObject или любому из его потомков. |
GetComponentsInParent | Возвращает все компоненты типа type в GameObject или любому из его родителей. |
SendMessage | Вызывает метод с названием methodName в каждом MonoBehaviour в этом игровом объекте. |
SendMessageUpwards | Вызывает метод с именем methodName в каждом MonoBehaviour в этом игровом объекте и в каждом предке поведения. |
TryGetComponent | Gets the component of the specified type, if it exists. |
GetInstanceID | Returns the instance id of the object. |
ToString | Returns the name of the object. |
Static Functions
Destroy | Removes a GameObject, component or asset. |
DestroyImmediate | Destroys the object obj immediately. You are strongly recommended to use Destroy instead. |
DontDestroyOnLoad | Do not destroy the target Object when loading a new Scene. |
FindObjectOfType | Returns the first active loaded object of Type type. |
FindObjectsOfType | Gets a list of all loaded objects of Type type. |
Instantiate | Clones the object original and returns the clone. |
Operators
bool | Does the object exist? |
operator != | Compares if two objects refer to a different object. |
operator == | Compares two object references to see if they refer to the same object. |
Можно ли использовать скрипты без наследования от MonoBehaviour?
По описанию на docs.unity3d.com я вижу, что наследование скриптов от MonoBehaviour в принципе не обязательно, дает разве что удобство получения информации о сцене и ее объектах. Но это так скучно, когда все сделали за вас да? В общем если я буду пытаться управлять объектом без скрипта потомка MonoBehaviour (допустим я смогу получать уведомление об обрисовке сцены и о всех GameObject), меня ждут какие-нибудь ошибки компиляции или выполнения?
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Можно ли использовать макрос без книги?
В макросе прописан скрип открывающий определенную книгу и поверх книги форму , в форме textbox’Ы.
Можно ли использовать Wi-fi роутер без модема?
В общем, интернет у нас подключен от телефонной линии (или как оно там называется) к модему, можно.
Можно ли использовать сайт, без SSL сертификатов?
Здравствуйте форумчане! Сегодня столкнулся с такой проблемой. После перехода на главную страницу.
MS SQL: можно ли использовать файл БД без СУБД
Народ вроде раньше где то читал что можно использовать файл базы от сервера MS SQL — без наличия.
295 / 244 / 128
Регистрация: 24.12.2014
Сообщений: 708
ATop, я, например, использую крайне редко наследование от MonoBehaviour или других похожих классов, так как почти не использую визуальный редактор. Скажу, что такое можно сделать, но есть подводные камни в плане вызова методов Update и FixedUpdate — могут возникнуть проблемы с наведением мыши ( в режиме, когда курсор скрыт ) и самой физикой ( некоторые методы будут работать некоректно ). Здесь нужно быть осторожным и тестировать всё заранее.
Я не любитель, чтобы мои классы наследовали ненужный мне хлам от MonoBehaviour, но некоторые вещи реализовать проще именно с MonoBehaviour.
Сообщение от ATop
меня ждут какие-нибудь ошибки компиляции
Это зависит, как и везде, только от написанного кода.
267 / 236 / 100
Регистрация: 26.10.2012
Сообщений: 699
Наследование от MonoBehaviour только позволяет добавлять скрипт на объект как компонент и принимать события вроде
Update, OnWillRenderObject, OnCollisionEnter.
Никто вам не запрещает использовать классы не-наследники, но:
1. Вам по-любому придется сделать класс MainManager, вызывающий все управляющие методы у дочерних классов.
Unity сам вызывает на все события MonoBehaviour в сцене, это уже оптимизировано на C++ — не факт, что вы сделаете это оптимальнее.
2. Иногда гораздо проще добавить класс как отдельный компонент на сцене со своей логикой, чем встраивать его в какой-то управляющий класс.
3. У MonoBehaviour классов проще реализовать ряд фич, вроде редактирования и сохранения на сцене.
4. Ну допустим события типа Start и Update вы можете сделать вне MonoBehaviour. Как вы сделаете остальные события, вроде
OnWillRenderObject, OnBecameVisible, OnCollisionEnter, OnCollisionStay? В лучшем случае через затратные костыли.
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
Помогаю со студенческими работами здесь
Можно ли использовать виртуальное окружение без активации?
То есть использовать интерпретатор с модулями но без активации
Можно ли использовать TCP протокол без winsock’а?
Можно ли использовать TCP протокол без winsock’а (т.е. без контрола)
Можно ли использовать PUT и DELETE запрос без ajax
с GET ($.get) и POST ($.post) все понятно. а можно ли PUT и DELETE тем же способом? Если.