Система компонентов C#
Система компонентов позволяет реализовать логику приложения с помощью набора строительных блоков — компонентов — и назначать эти блоки нодам, предоставляя им дополнительную функциональность. Комбинируя эти маленькие и простые блоки, вы можете создать очень сложную логическую систему.
Логический компонент объединяет ноду и класс C#, содержащий логическую реализацию (действия, которые необходимо выполнить), определяющий набор дополнительных параметров, которые будут использоваться.
Компоненты дают вам больше гибкости в реализации вашей логики, позволяя:
- управлять тем, какие части кода (реализованные как методы компонентов) должны выполняться, а какие нет;
- контролировать порядок выполнения этих частей кода;
- неоднократно использовать части кода, написанные один раз, для любого количества объектов без каких-либо изменений. Если вы хотите изменить свой код, вы меняете его в одном-единственном источнике (как в случае с NodeReference, если сравнивать с контентом);
- объединять определенные части кода, которые будут выполняться для определенных нод. Можно создать очень сложную систему из множества маленьких и простых блоков (это как использовать NodeReference для построения большой сложной структуры из множества простых нод).
Перед тем как начать писать код, нужно установить необходимое программное обеспечение .
Дополнительная информация#
- Отладка компонентов C# для получения дополнительных сведений об отладке кода ваших компонентов C#.
- Набор демо-проектов C# Component Samples, демонстрирующий различные способы использования компонентов C#.
- Платформер от третьего лица на C#, демонстрирующий производительность и гибкость логической системы с использованием знакомых концепций простого шутера от третьего лица.
- Системный API C#-компонентов для получения дополнительных сведений об управлении компонентами через C# API.
- Пример использования системы компонентов C# для получения дополнительных сведений о реализации логики с использованием системы компонентов C#.
Требования#
Для организации рабочего процесса программирования и создания проектов на основе .NET необходимо следующее:
- .NET SDK (для Windows и Linux)
-
IDE или текстовый редактор. Проверяется совместимость различных IDE со следующими версиями .NET:
IDE Поддерживаемая версия .NET MS Visual Studio Code 8.0.x MS Visual Studio 2022 8.0.x Visual Studio Code — рекомендуемый вариант.
Если вы работаете с MS Visual Studio Code, установите расширение C# для Visual Studio Code от OmniSharp при первом открытии компонента.
В случае возникновения каких-либо проблем с .NET, обратитесь к разделу "Устранение неполадок" в статье Проблемы с .NET.
Создание компонента#
Компоненты создаются в Редакторе. В Asset Browser нажмите правую кнопку мыши и выберите Create Code -> C# Component.
Укажите имя компонента в диалоговом окне, после чего в текущем каталоге браузера ассетов будет создан скриптовый файл C# с соответствующим именем.
Дважды щелкните на новом скриптовом файле, чтобы открыть его для редактирования логики компонента в IDE по умолчанию.
Переименование компонентов#
В идеале нужно с самого начала называть всё правильно. Название должно быть понятным и отражать то, что делает компонент. Но иногда что-то действительно меняется, и внезапно вы понимаете, что нужно изменить имя компонента. Начиная с версии 2.11 это не проблема. На самом деле переименование можно сделать двумя способами:
- Переименование cs-ассета в браузере ассетов. Класс компонента и связанное с ним свойство будут переименованы автоматически. Единственное, что нужно сделать в этом случае, — это заменить все ссылки на класс компонента в исходном коде на новые в вашей среде IDE через Find&Replace.
- Использование инструментов рефакторинга вашей IDE (например, Rename symbol в VS Code или Edit -> Refactor -> Rename в Visual Studio). После переименования просто откройте UnigineEditor — соответствующий cs-ассет и связанное с ним свойство будут переименованы автоматически с сохранением всех ссылок. Имейте в виду, что в этом случае имя cs-файла, содержащего реализацию вашего компонента, изменится, и файл будет удален из проекта вашей IDE как отсутствующий. То есть, вам придется добавить переименованный файл обратно в проект в среде IDE.
Структура компонента#
По сути, компоненты — это классы C#, унаследованные от базового класса Component.
Работа системы компонентов C# основана на свойствах . Когда вы создаете новый компонент, он автоматически регистрируется в Системе компонентов и создается внутреннее runtime-свойство и связывается с компонентом через GUID. Для правильной работы компонента необходим следующий атрибут класса Component.
[Component(PropertyGuid = "2ae011355ed7f110a202912faa000cc22276e539")]
Компоненты C# перечислены в иерархии Properties, изначально они унаследованы от базового свойства C# Components.
Простое наследование#
Предположим, у вас есть компонент, реализующий определенную функциональность, и вам нужно определенное количество подкомпонентов, имеющих точно такие же функциональные возможности, но разные значения параметров. Это обычная ситуация при реализации пресетов качества или конфигураций элементов управления. Просто унаследуйте свойство от базового компонента в UnigineEditor для каждого пресета и настройте необходимые значения параметров. После этого можно назначать эти унаследованные свойства нодам, таким образом присоединяя к ним логику базового компонента со значениями параметров, взятыми из унаследованных свойств. Без излишнего копирования, без избыточного кода.
Логика#
Логика компонентов реализована с помощью набора методов, которые вызываются соответствующими функциями скрипта world:
- Init() — создаются и инициализируются все необходимые ресурсы.
-
UpdateAsyncThread() — указываются все логические функции, которые вы хотите вызывать в каждом кадре независимо от потока рендеринга.
Этот метод не имеет защитных блокировок, поэтому не рекомендуется изменять другие компоненты внутри этого метода, если вы не уверены, что эти компоненты не будут изменены или удалены где-либо еще. -
UpdateSyncThread() — указываются все параллельные функции логики, которые вы хотите выполнить перед Update (). Этот метод можно использовать для выполнения некоторых ресурсоемких вычислений, таких как поиск пути, генерация процедурных текстур и т.д.
Этот метод следует использовать для вызова только тех методов API, которые относятся к текущей ноде: самой ноде, ее материалам и свойствам. - Update() — указываются все логические функции, которые должны вызываться в каждом кадре.
- PostUpdate() — корректируется поведение в соответствии с обновленными состояниями нод в том же кадре.
- UpdatePhysics() — выполняется симуляция физики: выполнение непрерывных операций (продвижение машины вперед в зависимости от оборотов двигателя, имитация постоянного ветра, выполнение немедленных реакций на столкновение и т. д.).
-
Swap() — работа с результатами метода updateAsyncThread() — все остальные методы (потоки) уже выполнены и ждут. После этой функции происходит только два действия:
- все объекты, поставленные в очередь на удаление, удаляются;
- выполняется обновление Профайлера.
- Shutdown() — выполняется очистка при выключении компонента.
Параметры#
У компонентов могут быть параметры, значения которых можно редактировать в окне Parameters.
Следующие объекты имеют автоматически сгенерированный пользовательский интерфейс в редакторе на основе типа данных и набора атрибутов:
- поля public класса компонента;
- любые поля private и protected поддерживаемых типов с опцией [ShowInEditor].
public int public_field;
private int private_field;
[ShowInEditor]
private float private_editable_field;
[HideInEditor]
public float public_hidden_field;
Параметры и их атрибуты могут быть объявлены для виджетов редактора.
Дополнительные сведения о поддерживаемых типах параметров и атрибутах см. в классе Component.
Применение логики компонентов к ноде#
Логическая реализация, описанная в компоненте, активна во время выполнения, только если компонент назначен на ноду, и обе ноды и компонент включены.
Есть несколько способов применения компонента к ноде:
-
Выберите ноду, щелкните Add New Property и введите имя ассета *.cs в разделе Node Properties вкладки Node. Вы можете сделать это, перетащив туда ассет *.cs из окна Asset Browser.
Также поддерживается перетаскивание на ноду в окне просмотра редактора.
- Добавьте компонент к ноде с помощью кода, используя функции ноды AddComponent<T>(Node node) и AddComponent<T>().
NewComponent component = AddComponent<NewComponent>(node);
NewComponent component = node.AddComponent<NewComponent>();
Логика определенного компонента применяется только тогда, когда компонент и соответствующая нода включены. Таким образом, при необходимости вы можете включать/отключать логику каждого конкретного компонента во время выполнения.
Вы можете назначить несколько компонентов одной ноде. Последовательность, в которой выполняется логика компонентов, определяется значением order, указанным для соответствующих методов (если значения order совпадают или не указаны, последовательность неопределима).
Компоненты могут взаимодействовать с другими компонентами и нодами.
Запуск проекта#
Чтобы запустить проект, нажмите кнопку Play на панели инструментов. Это запустит экземпляр приложения в отдельном окне.
Чтобы в Windows сообщения об ошибках отображались корректно, язык для программ, не поддерживающих Юникод, должен быть таким же, как текущий языковой стандарт системы.
В списке доступны пресеты пользовательских параметров запуска. По умолчанию выставлен пресет Default (Debug) со стандартными параметрами запуска. Нажмите на значок шестеренки, чтобы настроить текущий выбранный пресет пользовательских параметров запуска.
В открывшемся окне доступны следующие варианты запуска:
Конфигурация | Используемая сборка UNIGINE Engine |
---|---|
Video API |
Графический API, используемый для рендеринга:
|
Resolution | Размер экрана |
Fullscreen |
Настройка полноэкранного режима, запуск экземпляра в одном из следующих режимов:
|
VR Mode |
Включить совместимость с одной из поддерживаемых гарнитур VR:
|
Video Debug |
Включает контекст отладки Vulkan или DirectX:
|
Materials Loading Mode |
Выбор режима загрузки материалов:
|
Run Current World | Запуск текущего мира, открытого в редакторе, независимо от того, какой мир по умолчанию установлен логикой. |
Arguments | Набор параметров командной строки запуска . |
При изменении любого пользовательского параметра запуска и закрытии окна в зависимости от выбранной предустановки будут выполнены следующие действия:
- Если в списке выбрана предустановка Default (Debug), в текущей папке браузера ассетов будет создан новый файл ассетов *.launch , содержащий настраиваемые параметры запуска. Соответствующий пресет будет доступен в списке пресетов.
- Если выбран другой пресет, к нему будут применены изменения.
Отладка C# компонентов #
UnigineEditor автоматически перекомпилирует компоненты C# по мере того как вы вносите изменения в код, сохраняете их и возвращаетесь в редактор. Вы увидите зеленое уведомление об успешной компиляции, а красное сигнализирует об обнаружении ошибок. При нажатии на красное сообщение в консоли отображаются подробные сведения.
Вы можете проверить исходный код компонентов C# во время работы вашего приложения, независимо от того, запущено ли приложение с помощью кнопки Play прямо в UnigineEditor или создано и запущено из IDE.
Подробности см. в статье Отладка компонентов C# .
Сборка приложения#
Чтобы создать отладочную или финальную сборку вашего приложения C#, используйте опцию File -> Create Build, доступную в UnigineEditor.
Подробности см. в статье Финальная сборка проекта для публикации .
Использование#
В качестве примера, можно использовать компоненты для реализации логики преследования врагами в вашей игре: независимо от их размера, формы, скорости, все они будут проверять позицию игрока и пытаться найти путь, по которому можно максимально быстро дойти до игрока. Код будет по большей части одинаковым, могут различаться лишь параметры (скорость, меш и, возможно, звуки), поэтому можно добавить все эти параметры в компонент (чтобы можно было изменять их в любое время) и в код соответствующего класса компонента (например, добавление врагов в мире в методе Init() и преследование игрока в методе Update()).
Затем нужно просто назначить компонент всем объектам врагов и настроить параметры (определить меши, звуки и т. д.). Система компонентов сделает все остальное: выполнит ваш код на соответствующих этапах основного цикла Engine для всех объектов врагов, используя их конкретные параметры. Если вы впоследствии захотите изменить код, это можно сделать в одном единственном месте — классе компонента.
Интеграция с инструментом Microprofile позволяет контролировать общую производительность системы компонентов, а также добавлять необходимую информацию по компонентам.