Работа с компонентами в Редакторе
C++ components in Editor are not managed directly, but rather via the associated properties. Unlike C# components that you can create right in UnigineEditor, C++ components are to be added to your C++ project via the IDE first, then compiled, and then registered by the Component System, which generates associated properties to be assigned to nodes in UnigineEditor.В UnigineEditor работа с C++ компонентами организована не напрямую, а через ассоциированные с этими компонентами свойства (property). В отличие от C# компонент, которые можно создавать прямо в UnigineEditor, C++ компоненты сначала необходимо добавить в ваш C++ проект в среде программирования(IDE), скомпилировать их, а затем зарегистрировать в Компонентной системе, которая сгенерирует для них ассоциированные свойства (property). Именно эти свойства назначаются нодам в UnigineEditor, чтобы добавить к ним логику компонент.
WorkflowПорядок работы#
To add a C++ component you should do the following:Для добавления C++ компонента необходимо выполнить следующие шаги:
1. Open Project in IDE1. Открытие проекта в IDE#
First, open your project in an IDE (Microsoft Visual Studio is recommended) - go to SDK Browser and choose Open Code IDE on your project's card.Первым делом, откройте код вашего проекта в IDE (рекомендуется использовать Microsoft Visual Studio) - переключитесь в SDK Browser и щелкните Open Code IDE на карточке вашего проекта.
2. Add New C++ Component Class2. Добавление класса нового C++ компонента#
In an IDE create a new C++ class (Project → Add Class) and call it MyComponent.В IDE создайте новый C++ класс (Project → Add Class) и назовите его MyComponent.
Make sure it inherits from the ComponentBase class. You can build a whole hierarchy using your own components, by inheriting some components from others in accordance with the OOP principles (we'll review this in detail later).Убедитесь, что он отнаследован от базового класса ComponentBase. Из своих компонентов вы можете построить целую иерархию, наследуя одни компоненты от других – все в соответствии с принципами ООП (об этом чуть позже).
Two files*.h and *.cpp will be added to your C++ project.К вашему C++ проекту будет добавлено два файла (*.h и *.cpp).
3. Write Component Code3. Написание кода компонента#
Header File (*.H)Заголовочный файл (*.H)#
In the header file (MyComponent.h) you should do the following:В заголовочном файле (MyComponent.h) сделайте следующее:
-
Declare a component class using the following macro:Объявите класс компонента, используя следующий макрос:
COMPONENT_DEFINE(MyComponent, Unigine::ComponentBase);
Class name defines the name of the property (the corresponding *.prop file is automatically saved in your project's data folder).Имя класса определяет имя свойства (property), соответствующий файл с расширением *.prop автоматически сохраняется в папке data вашего проекта.
-
Declare parameters with their default values (if any). The simplest way to declare a parameter is to use the following macro (optional arguments are enclosed in square brackets []):Объявите параметры компонента, указав значения по умолчанию (при наличии). Самый простой способ определить параметр - использовать макрос (необязательные аргументы указаны в квадратных скобках []):
PROP_PARAM(param_type, name[, default_value, title, tooltip, group]);
A set of macros enables you to define multiple types of component parameters to be displayed and adjusted in UnigineEditor. See the the ComponentBase class documentation for the detailed information about supported parameter types and attributes.Набор макросов позволяет вам определить широкий спектр параметров компонента, которые можно просматривать и настраивать в Редакторе. Более подробную информацию о поддерживаемых типах параметров и дополнительных атрибутах вы можете найти в документации класса ComponentBase.
The list of available macros includes the following ones to declare complex-type parameters (arrays, structures, and arrays of structures):Для объявления комплексных параметров (массивы, структуры, массивы структур) список макросов также включает следующие:
PROP_STRUCT(type, name); PROP_ARRAY(type, name); PROP_ARRAY_STRUCT(type, name);
-
Declare which methods you are going to use to implement component's logic, and during which stages of the execution sequence to call them:Определите методы, которые будут использоваться для реализации логики компонента, а также на каких этапах рабочего цикла приложения они будут выполняться:
public: COMPONENT_INIT(my_init); COMPONENT_UPDATE(my_update); COMPONENT_SHUTDOWN(my_shutdown); // ... protected: void my_init(); void my_update(); void my_shutdown();
- Declare all necessary auxiliary parameters and functions.Определите все необходимые дополнительные параметры и функции.
Implementation File (*.CPP)Файл реализации (*.CPP)#
In the implementation file (MyComponent.cpp) you should do the following:В файле реализации (MyComponent.cpp) сделайте следующее:
-
Register the component class in the Component System using the following macro:Зарегистрируйте класс компонента в Компонентной системе, используя следующий макрос:
REGISTER_COMPONENT(MyComponent);
- Implement your component's logic in the methods that you've declared in the header file.Реализуйте логику компонента внутри методов, которые вы объявили в заголовочном файле.
We'll make a simple component that will rotate a node to which it is assigned every frame at a certain angle. Summarizing all the things above we can make our component look like it is shown below. You can copy the code, paste it to the corresponding files in your project and save them in your IDE.Напишем простой компонент, который каждый кадр будет поворачивать ноду, на которую он назначен, на определенный угол. Собирая воедино все вышесказанное, получим приведенный ниже код компонента. Его можно скопировать и вставить в соответствующие файлы вашего проекта в IDE и сохранить изменения.
#pragma once
// include the ComponentSystem header
#include <UnigineComponentSystem.h>
class MyComponent :
public Unigine::ComponentBase
{
// Объявляем конструктор и деструктор для нашего класса, а также задаем имя связанного с компонентом свойства (property).
// Файл MyComponent.prop со всеми описанными ниже параметрами будет сгенерирован Компонентной системой в папке 'data' вашего проекта при первом запуске приложения
COMPONENT_DEFINE(MyComponent, Unigine::ComponentBase);
// объявляем параметры компонента и задаем начальные значения
PROP_PARAM(Float, angle, 10.0f, "Angle", "Node rotation angle", 0, "max=360;min=0");
// регистрация методов, которые будут вызываться на соответствующих этапах жизненного цикла приложения (сами методы объявляются в protected-блоке ниже)
COMPONENT_UPDATE(update);
protected:
// объявление методов, которые будут вызываться на соответствующих этапах жизненного цикла приложения
void update();
};
#include "MyComponent.h"
// Регистрация компонента MyComponent в Компонентной системе
REGISTER_COMPONENT(MyComponent);
using namespace Unigine;
using namespace Math;
// метод, который будет вызываться каждый кадр
void MyComponent::update()
{
// поворачиваем объект вокруг оси Z на угол, заданный параметром (Angle)
node->rotate(0.0f, 0.0f, angle);
}
4. Compile And Run To Generate Property4. Компиляция и сборка для генерации свойства (property)#
Don't forget to set the appropriate platform and configuration settings for your project before compiling your code in Visual Studio.Не забудьте выбрать нужную конфигурацию сборки для своего проекта прежде, чем запускать компиляцию в Visual Studio.
Build and run your application by hitting Ctrl + F5 to make the Component System register the component and generate an associated property with the corresponding set of parameters (according to your component's class declaration) to be used to assign the component to nodes. Close the application after running it and switch to UnigineEditor.Соберите и запустите свое приложение, нажав Ctrl + F5, чтобы Компонентная система зарегистрировала компонент и сгенерировала ассоциированное свойство (property) с соответствующим набором параметров (согласно определению класса компонента), которое будет использоваться для связи компонента с нодами. После запуска приложения закройте его и вернитесь в UnigineEditor.
5. Assign Component To Nodes In Editor5. Назначение компонента на ноды в Редакторе#
After successful registration all available properties associated with your C++ components are displayed in the Properties window as children of the basic node_base property.После успешной регистрации компонент, все доступные свойства (property) ассоциированные с вашими C++ компонентами появятся в окне Properties как дочерние элементы базового свойства node_base.
The component is ready, but now it must be assigned to some node, otherwise its code won't be executed. Decide which object you want to rotate (e.g. Material Ball), drag the property (MyComponent.cpp) from the Properties hierarchy and drop onto this object (you can drop it on the object directly in the viewport or on the node in the World Nodes window).Компонент готов, но его еще нужно назначить на ноду, чтобы его код начал работать. Определите, какой объект вы хотите повращать (например, пусть это будет Material Ball из стандартного мира), перетащите свойство MyComponent.cpp из иерархии Properties прямо на этот объект (либо непосредственно во вьюпорте, либо в окне иерархии сцены World Nodes).
In the Parameters window set the desired Angle value with a slider and save the world by hitting Ctrl + S.В окне Parameters при помощи слайдера установите желаемое значение угла (Angle) и сохраните изменения в мире, нажав Ctrl + S.
The component can be assigned to a node via code as well:Также компонент к ноде можно добавить из кода:
// так:
ComponentSystem::get()->addComponent<MyComponent>(node);
// или вот так (через назначение свойства ассоциированного с компонентом):
node->addProperty("mycomponent_prop_name");
Now, we're ready to launch our application via the SDK Browser by selecting the project on the Projects tab and clicking Run. But before doing so let's make sure, that appropriate Customize Run Options (Debug version in our case) are selected, by clicking an ellipsis under the Run button (check Debug and Remember then click Run).Теперь мы готовы запустить наше приложение через SDK Browser, выбрав карточку проекта в списке на вкладке Projects и нажав Run. Но, прежде чем мы это сделаем, давайте установим конфигурацию запуска в окне Customize Run Options (включим версию Debug в нашем случае), для этого щелкнем на многоточие рядом с кнопкой Run (отметьте Debug и Remember, чтобы запомнить настройки, а затем щелкните Run).
Check if the object rotates as intended!Убедитесь, что объект вращается как задумано!
Hierarchy and Inheritance, Overriding Parameters and Overloading MethodsИерархия и наследование, переопределение параметров и перегрузка методов#
Suppose you have a component that implements a certain functionality, and you need a certain number of subcomponents that have exactly the same functionality but different parameter values. This is a common situation when implementing quality presets or control configurations. Simply inherit a property from the base component in the Editor for each preset and configure the required parameter values. You can then assign these inherited properties to nodes, thus attaching the logic of the base component with parameter values taken from the inherited properties. No unnecessary copying, no redundant code.Предположим, у вас есть компонент, реализующий определенную функциональность, и вам нужно определенное количество подкомпонент, имеющих точно такие же функциональные возможности, но разные значения параметров. Это обычная ситуация при реализации пресетов качества или конфигураций элементов управления. Просто унаследуйте свойство от базовой компоненты в Редакторе для каждого пресета и настройте необходимые значения параметров. После этого можно назначать эти унаследованные свойства нодам, таким образом присоединяя к ним логику базового компонента со значениями параметров, взятыми из унаследованных свойств. Без излишнего копирования, без избыточного кода.
In addition to overriding parameter values, you can also extend the functionality of base components in child components. This is done in accordance with the OOP concept by inheriting the child component class from the base component class, for example:Помимо переопределения значений параметров, можно расширять и функционал базовых компонент в дочерних. Делается это в соответствии с концепцией ООП путем наследования класса дочерней компоненты от класса базовой, например:
// Класс Interactable наследник базового класса ComponentBase
class Interactable : public Unigine::ComponentBase
{
public:
COMPONENT_DEFINE(Interactable, ComponentBase);
// параметр
PROP_PARAM(String, tooltip, "Info about the object");
// виртуальный метод реализующий действие (в дочерних классах)
virtual void action(int num = 0) {};
};
// ------------------------------------------------------------------
// Класс Toggle наследник класса Interactable
class Toggle : public Interactable
{
public:
COMPONENT_DEFINE(Toggle, Interactable);
// дополнительный параметр
PROP_PARAM(Node, controlNode, nullptr);
// ...
// перегрузка родительского метода Action
void action(int num = 0)
{
if (num != 0)
return;
Unigine::Log::message("Toggle action for: %s \n ", node->getName());
// ...
}
// расширение родительского функционала новым методом
void someNewMethod()
{
//...
}
// ...
};
We'll review more examples a bit later.Подробнее разберем на конкретных примерах чуть позднее.
Debugging ComponentsОтладка компонент#
The Microsoft Visual Studio environment is known for its excellent debugging tools. You can test the source code of C++ components while your application is running, whether the application is launched via the SDK Browser or created and running from the IDE.Среда Microsoft Visual Studio известна своими отличными инструментами отладки. Можно проверить исходный код компонентов C# во время работы вашего приложения, независимо от того, запущено ли приложение через SDK Browser (Attach) или создано и запущено из IDE.
Debugging in IDEОтладка в IDE#
To compile all your components, build the application, and debug it by running it directly from the IDE, select Debug → Start Debugging (or press F5):Чтобы скомпилировать все ваши компоненты, собрать приложение и отладить его, запустив его прямо из IDE, вы должны выбрать Debug → Start Debugging (или нажать F5):
Now you can add the necessary breakpoints and just press F5 to start the debugging process.Теперь вы можете добавить необходимые точки останова и просто нажать F5, чтобы запустить процесс отладки.
At startup, the application will run with the world set for your project in SDK Browser at creation. If the default world is not set, you will see a black screen after launching the app. In this case, you can open the console (press "~" on the keyboard) and load the desired world using the world_load <world_name> console command.При запуске приложение будет работать с миром, установленным для вашего проекта Браузером SDK при создании. Если мир по умолчанию не установлен, после запуска приложения вы увидите черный экран. В этом случае вы можете открыть консоль (нажмите "~" на клавиатуре) и загрузить желаемый мир с помощью консольной команды: world_load <имя_мира>.
Attaching to Running ApplicationПодключение к запущенному приложению#
You can also connect Visual Studio debugger to an instance of your application that is already running. The most common case is launching it via the SDK Browser. Just add necessary breakpoints and select Debug → Attach To Process from the main menu.Вы также можете подключить отладчик Visual Studio к экземпляру вашего приложения, которое уже запущено. Например, запуск приложения через SDK Browser. Просто добавьте нужные точки останова и выберите Debug → Attach To Process в главном меню Visual Studio.
Type your project's name in the search field in the Available processes section to find the process you need. Select it in the list and click AttachЧтобы найти нужный вам процесс, введите имя своего проекта в поле поиска в разделе Available processes. Затем выберите процесс в списке и щелкните Attach
Setting BreakpointsУстановка точек останова#
Breakpoints are used to pause your application by stopping execution of your code and giving you a chance to inspect and analyze your program's operation. You can check values of variables, and move step-by-step through your code.Точки останова используются для приостановки вашего приложения, выполнение вашего кода прерывается и вы получаете возможность проверить и проанализировать работу своей программы. Вы можете проверять значения переменных и двигаться по коду по шагам.
To set up a breakpoint put the cursor to the desired line of your code and press F9 or use the menu.Чтобы установить точку останова, поместите курсор на нужную строку вашего кода и нажмите F9 или используйте меню.