This page has been translated automatically.
Видеоуроки
Интерфейс
Основы
Продвинутый уровень
Подсказки и советы
Основы
Программирование на C#
Рендеринг
Профессиональный уровень (SIM)
Принципы работы
Свойства (properties)
Компонентная Система
Рендер
Физика
Редактор UnigineEditor
Обзор интерфейса
Работа с ассетами
Контроль версий
Настройки и предпочтения
Работа с проектами
Настройка параметров ноды
Setting Up Materials
Настройка свойств
Освещение
Sandworm
Использование инструментов редактора для конкретных задач
Расширение функционала редактора
Встроенные объекты
Ноды (Nodes)
Объекты (Objects)
Эффекты
Декали
Источники света
Geodetics
World-ноды
Звуковые объекты
Объекты поиска пути
Player-ноды
Программирование
Основы
Настройка среды разработки
Примеры использования
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Плагины
Форматы файлов
Материалы и шейдеры
Rebuilding the Engine Tools
Интерфейс пользователя (GUI)
VR Development
Двойная точность координат
API
Animations-Related Classes
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
VR-Related Classes
Работа с контентом
Оптимизация контента
Материалы
Визуальный редактор материалов
Сэмплы материалов
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Учебные материалы

Создание пользовательских компонентов

Внимание
Функционал, описанный в этой статье, недоступен в Community редакции SDK.
Чтобы использовать этот функционал вам необходимо получить лицензию на Sim SDK.

Вы можете расширить исходный набор компонентов, которые могут быть добавлены к сущностям, добавив собственные. В качестве примера рассмотрим добавление компонента капли воды для самолета Бе-200, доступного в IG Template.

Рабочий процесс#

Follow the instructions given below to create you own custom component.Следуйте приведенным ниже инструкциям, чтобы создать собственный пользовательский компонент.

  1. Create a new project using the IG Template as described here.Создайте новый проект, используя IG Template и Компонентную систему С++ как описано здесь .

    Create a Project using the IG Template and Component System

  2. Добавьте следующий код инициализации для Компонентной системы в метод AppSystemLogic::init() в файле AppSystemLogic.cpp:

    Исходный код (C++)
    virtual int AppSystemLogic::init()
    {
    	// initialize ComponentSystem and register all components
    	Unigine::ComponentSystem::get()->initialize();
    
    	/*...*/
    	
    	return 1;
    }
  3. Create the following files describing your new component to the C++ project:Создайте (или добавьте) следующие файлы с описанием вашего нового компонента в проект C ++:

    Примечание

    Компонент должен быть унаследован от классов ComponentBase и ComponentBaseInterface.

    Если вы хотите синхронизировать свой компонент (его внутреннее состояние, любые параметры, команды и т.д.), вы можете переопределить следующие методы:

    • saveState() - для синхронизации данных компонента записи кода с blob на Master.
    • restoreState() - для кода, считывающего данные из blob на Slaves.
    • WaterDropAircraftController.h

      Исходный код (C++)
      #pragma once
      
      #include <UnigineGame.h>
      #include <plugins/Unigine/IG/UnigineIG.h>
      #include <UnigineComponentSystem.h>
      
      class WaterDropAircraftController final: public Unigine::ComponentBase
      {
      public:
      	COMPONENT(WaterDropAircraftController, Unigine::ComponentBase);
      	COMPONENT_INIT(init);
      	COMPONENT_UPDATE(update);
      	COMPONENT_SHUTDOWN(shutdown);
      	// Specifying the name of the property file and parameters for our component
      	PROP_NAME("WaterDropAircraftController");
      	PROP_PARAM(Toggle, open, false, "Open", "Input parameter for enabling/disabling the effect", "Input");
      	PROP_PARAM(Float, normalize_flow, 1.0f, "Normalize Flow", "Input parameter for the effect power normalization", "Input");
      	PROP_PARAM(Float, normalize_payload, 1.0f, "Normalize Payload", "Input parameter for payload normalization", "Input");
      
      	PROP_PARAM(Node, particles_system, "Particles System", "ObjectParticles with the effect", "Effect");
      	PROP_PARAM(Float, spawn_rate_factor, 100.0f, "Spawn Rate Factor", "Multiplier for spawn rate", "Effect");
      
      	PROP_PARAM(Toggle, controlled_payload_time, false, "Controlled Payload Time", "Enable: water effect can be stopped automatically", "Payload")
      	PROP_PARAM(Float, max_water_payload, 100.0f, "Max Water Payload", "Full water payload in units (weight or volume)", "Payload")
      	PROP_PARAM(Float, max_flow_speed, 1.0f, "Max Flow Speed", "Maximum water flow speed (units per second)", "Payload");
      private:
      	void init();
      	void update();
      	void shutdown();
      
      	// Declaring a callback on changing the property parameters
      	void parameterChanged(Unigine::PropertyPtr property, int propID);
      
      	void openWaterDropSystem(bool open);
      	void setWaterDropSystemFlow(float value);
      	void setWaterPayload(float value);
      
      private:
      	// Declaring a particle system to be used for the water drop effect
      	Unigine::ObjectParticlesPtr dropWaterEffect;
      
      	float current_payload = 0.0f;
      	Unigine::Plugins::IG::Manager *ig = nullptr;
      };

      WaterDropAircraftController.h

      Исходный код (C++)
      #ifndef _WATER_DROP_AIRCRAFT_CONTROLLER_INCLUDED_
      #define _WATER_DROP_AIRCRAFT_CONTROLLER_INCLUDED_
      
      #include <UnigineGame.h>
      #include <plugins/Unigine/IG/UnigineIG.h>
      #include <UnigineComponentSystem.h>
      
      class WaterDropAircraftController final : public Unigine::ComponentBase, public Unigine::Plugins::IG::ComponentBaseInterface
      {
      public:
      	COMPONENT(WaterDropAircraftController, Unigine::ComponentBase);
      	COMPONENT_INIT(init);
      	COMPONENT_UPDATE(update);
      	COMPONENT_SHUTDOWN(shutdown);
      	
      	// Specifying the name of the property file and parameters for our component
      	PROP_NAME("WaterDropAircraftController");
      	PROP_PARAM(Toggle, open, false, "Open", "Input parameter for enabling/disabling the effect", "Input");
      	PROP_PARAM(Float, normalize_flow, 1.0f, "Normalize Flow", "Input parameter for the effect power normalization", "Input");
      	PROP_PARAM(Float, normalize_payload, 1.0f, "Normalize Payload", "Input parameter for payload normalization", "Input");
      
      	PROP_PARAM(Node, particles_system, "Particles System", "ObjectParticles with the effect", "Effect");
      	PROP_PARAM(Float, spawn_rate_factor, 100.0f, "Spawn Rate Factor", "Multiplier for spawn rate", "Effect");
      
      	PROP_PARAM(Toggle, controlled_payload_time, false, "Controlled Payload Time", "Enable: water effect can be stopped automatically", "Payload")
      	PROP_PARAM(Float, max_water_payload, 100.0f, "Max Water Payload", "Full water payload in units (weight or volume)", "Payload")
      	PROP_PARAM(Float, max_flow_speed, 1.0f, "Max Flow Speed", "Maximum water flow speed (units per second)", "Payload");
      
      private:
      	void init();
      	void update();
      	void shutdown();
      	
      	// Declaring a callback on changing the property parameters
      	void parameterChanged(Unigine::PropertyPtr property, int propID);
      
      	void openWaterDropSystem(bool open);
      	void setWaterDropSystemFlow(float value);
      	void setWaterPayload(float value);
      
      private:
      	// Declaring a particle system to be used for the water drop effect
      	Unigine::ObjectParticlesPtr dropWaterEffect;
      
      	float current_payload = 0.0f;
      	Unigine::Plugins::IG::Manager *ig = nullptr;
      
      	void saveState(const Unigine::BlobPtr &blob) override;
      	void restoreState(const Unigine::BlobPtr &blob) override;
      };
      
      #endif // _WATER_DROP_AIRCRAFT_CONTROLLER_INCLUDED_
    • WaterDropAircraftController.cpp

      Исходный код (C++)
      #include "WaterDropAircraftController.h"
      #include <UnigineProperties.h>
      #include <UnigineObjects.h>
      #include <UnigineEditor.h>
      // Registering the component in the Component System
      REGISTER_COMPONENT(WaterDropAircraftController);
      using namespace Unigine;
      
      void WaterDropAircraftController::init()
      {
      
      	// Adding a callback on changing the property parameters
      	getProperty()->addCallback(Property::CALLBACK_PARAMETER_CHANGED,
      		MakeCallback(this, &WaterDropAircraftController::parameterChanged));
      	// Creating a particle system for our effect and setting its parameters
      	dropWaterEffect = checked_ptr_cast<ObjectParticles>(particles_system.get());
      	if (!dropWaterEffect)
      		Log::error("WaterDropAircraftController::init(): particles_system node is not ObjectParticles!\n");
      	else
      		dropWaterEffect->setEmitterEnabled(false);
      
      	ig = Plugins::IG::Manager::get();
      }
      void WaterDropAircraftController::update()
      {
      	if (! dropWaterEffect || controlled_payload_time == 0 || open == 0 || normalize_flow <= 0 || current_payload <= 0)
      		return;
      
      	if (!dropWaterEffect->isEmitterEnabled())
      		dropWaterEffect->setEmitterEnabled(true);
      
      	// decrease current payload
      	current_payload -= ig->getIFps() * normalize_flow * max_flow_speed;
      
      	// if payload is empty - disable effect
      	if (current_payload < 0)
      		dropWaterEffect->setEmitterEnabled(false);
      }
      
      void WaterDropAircraftController::shutdown()
      {}
      
      /// Callback function to be executed on changing property parameters
      void WaterDropAircraftController::parameterChanged(Unigine::PropertyPtr prop, int propID)
      {
      	if (open.getID() == propID)
      		openWaterDropSystem(prop->getParameterPtr(propID)->getValueToggle());
      	else if (normalize_flow.getID() == propID)
      		setWaterDropSystemFlow(prop->getParameterPtr(propID)->getValueFloat());
      	else if (normalize_payload.getID() == propID)
      		setWaterPayload(prop->getParameterPtr(propID)->getValueFloat());
      }
      
      void WaterDropAircraftController::openWaterDropSystem(bool value)
      {
      	if (dropWaterEffect)
      		dropWaterEffect->setEmitterEnabled(value);
      }
      
      void WaterDropAircraftController::setWaterDropSystemFlow(float value)
      {
      	if (dropWaterEffect)
      		dropWaterEffect->setSpawnRate(value * spawn_rate_factor.get());
      }
      
      void WaterDropAircraftController::setWaterPayload(float value)
      {
      	current_payload = value * max_water_payload;
      }

      WaterDropAircraftController.cpp

      Исходный код (C++)
      #include "WaterDropAircraftController.h"
      #include <UnigineProperties.h>
      #include <UnigineObjects.h>
      #include <UnigineEditor.h>
      // Registering the component in the Component System
      REGISTER_COMPONENT(WaterDropAircraftController);
      
      void WaterDropAircraftController::init()
      {
      	using namespace Unigine;
      	// Adding a callback on changing the property parameters
      	getProperty()->addCallback(Property::CALLBACK_PARAMETER_CHANGED,
      		MakeCallback(this, &WaterDropAircraftController::parameterChanged));
      
      	// Creating a particle system for our effect and setting its parameters
      	dropWaterEffect = checked_ptr_cast<ObjectParticles>(particles_system.get());
      	if (!dropWaterEffect)
      		Log::error("WaterDropAircraftController::init(): particles_system node is not ObjectParticles!\n");
      	else
      		dropWaterEffect->setEmitterEnabled(false);
      
      	ig = Plugins::IG::Manager::get();
      }
      
      void WaterDropAircraftController::update()
      {
      	if (! dropWaterEffect || controlled_payload_time == 0 || open == 0 || normalize_flow <= 0 || current_payload <= 0)
      		return;
      	
      	if (!dropWaterEffect->isEmitterEnabled())
      		dropWaterEffect->setEmitterEnabled(true);
      	
      	// decrease current payload
      	current_payload -= ig->getIFps() * normalize_flow * max_flow_speed;
      
      	// if payload is empty — disable effect
      	if (current_payload < 0)
      		dropWaterEffect->setEmitterEnabled(false);
      }
      
      void WaterDropAircraftController::shutdown()
      {}
      
      /// Callback function to be executed on changing property parameters
      void WaterDropAircraftController::parameterChanged(Unigine::PropertyPtr prop, int propID)
      {
      	if (open.getID() == propID)
      		openWaterDropSystem(prop->getParameterPtr(propID)->getValueToggle());
      	else if (normalize_flow.getID() == propID)
      		setWaterDropSystemFlow(prop->getParameterPtr(propID)->getValueFloat());
      	else if (normalize_payload.getID() == propID)
      		setWaterPayload(prop->getParameterPtr(propID)->getValueFloat());
      }
      
      void WaterDropAircraftController::openWaterDropSystem(bool value)
      {
      	if (dropWaterEffect)
      		dropWaterEffect->setEmitterEnabled(value);
      }
      
      void WaterDropAircraftController::setWaterDropSystemFlow(float value)
      {
      	if (dropWaterEffect)
      		dropWaterEffect->setSpawnRate(value * spawn_rate_factor.get());
      }
      
      void WaterDropAircraftController::setWaterPayload(float value)
      {
      	current_payload = value * max_water_payload;
      }
      
      void WaterDropAircraftController::saveState(const BlobPtr &blob)
      {
      	// master logic 
      	// when new slave is connected
      	blob->writeBool(open > 0);
      	blob->writeFloat(normalize_flow);
      	blob->writeFloat(current_payload);
      }
      
      void WaterDropAircraftController::restoreState(const BlobPtr &blob)
      {
      	// slave logic
      	// new slave received these parameters
      	open = blob->readBool();
      	normalize_flow = blob->readFloat();
      	current_payload = blob->readFloat();
      }

    In the header file (WaterDropAircraftController.h) define the name for the property file and describe parameters of the component: В заголовочном файле (WaterDropAircraftController.h) определите имя для файла свойств и опишите параметры компонента:

    Исходный код (C++)
    // WaterDropAircraftController.h
    	// ...
        // Specifying the name of the property file and parameters for our component
        PROP_NAME("WaterDropAircraftController");
        PROP_PARAM(Toggle, open, false, "Open", "Input parameter for enabling/disabling the effect", "Input");
    	PROP_PARAM(Float, normalize_flow, 1.0f, "Normalize Flow", "Input parameter for the effect power normalization", "Input");
    	
    	// ...

    In the implementation file (WaterDropAircraftController.cpp) write your component's logic. At the initialization stage subscribe to parameter change event, as this component (property) will be associated with IG components changing these parameters when receiving commands from a host.В файле реализации (WaterDropAircraftController.cpp) напишите логику вашего компонента. На этапе инициализации подпишитесь на событие изменения параметра, так как этот компонент (свойство) будет связан с компонентами IG, изменяющими эти параметры при получении команд от хоста.

    Исходный код (C++)
    // WaterDropAircraftController.cpp)
    	// ...
        
        void WaterDropAircraftController::init()
        {
        	using namespace Unigine;
    		
    		// Adding a callback on changing property parameters
        	getProperty()->addCallback(Property::CALLBACK_PARAMETER_CHANGED,
        		MakeCallback(this, &WaterDropAircraftController::parameterChanged));
                // ...
        }
  4. Build and launch your project. At the initialization stage the Component System will create a property file named WaterDropAircraftController.prop for our component.Создайте и запустите свой проект. На этапе инициализации Компонентная система создаст файл свойств с именем WaterDropAircraftController.prop для нашего компонента.

    Исходный код (XML)
    <?xml version="1.0" encoding="utf-8"?>
    <property version="2.7.3.0" name="WaterDropAircraftController" manual="1" parent_name="node_base">
    	<parameter name="open" type="toggle" title="Open" tooltip="Input parameter for enabling/disabling the effect" group="Input">0</parameter>
    	<parameter name="normalize_flow" type="float" title="Normalize Flow" tooltip="Input parameter for the effect power normalization" group="Input">1</parameter>
    	<parameter name="normalize_payload" type="float" title="Normalize Payload" tooltip="Input parameter for payload normalization" group="Input">1</parameter>
    	<parameter name="particles_system" type="node" title="Particles System" tooltip="ObjectParticles with the effect" group="Effect">0</parameter>
    	<parameter name="spawn_rate_factor" type="float" title="Spawn Rate Factor" tooltip="Multiplier for spawn rate" group="Effect">100</parameter>
    	<parameter name="controlled_payload_time" type="toggle" title="Controlled Payload Time" tooltip="Enable: water effect can be stopped automatically" group="Payload">0</parameter>
    	<parameter name="max_water_payload" type="float" title="Max Water Payload" tooltip="Full water payload in units (weight or volume)" group="Payload">100</parameter>
    	<parameter name="max_flow_speed" type="float" title="Max Flow Speed" tooltip="Maximum water flow speed (units per second)" group="Payload">1</parameter>
    </property>
  5. Via the UNIGINE Editor, assign the new created property file (WaterDropAircraftController.prop) to a node, for which the component was created (Be-200 in our case).Через UnigineEditor назначьте новый созданный файл свойств (WaterDropAircraftController.prop) узлу, для которого был создан компонент (в нашем случае Be-200).

    Create a Particle System in the UNIGINE Editor and set its parameters as required. Add this Particle System to the corresponding field of the property.Создайте Систему частиц в UnigineEditor и задайте необходимые параметры. Добавьте эту систему частиц в соответствующее поле свойства.

  6. Add the description of our component to the desired entity in the IG configuration file (ig_config.xml). Its name and parameters must correspond to the ones described in the component's header file (see Step 3).Добавьте описание нашего компонента к желаемой сущности в Файл конфигурации IG (ig_config.xml). Его имя и параметры должны соответствовать описанным в заголовочном файле компонента (см. Шаг 3 ) .

    Исходный код (XML)
    <!-- ..... -->
    	<entity id="200" name="be-200">
    		<!-- ..... -->
    		<component id="6" name="water_drop">
                    <property>WaterDropAircraftController</property>
                    <parameter name="state">open</parameter>
                    <parameter name="data1">normalize_flow</parameter>
                    <parameter name="data2">normalize_payload</parameter>
    				<!-- ..... -->
    		</component>
    		<!-- ..... -->
    	</entity>
    <!-- ..... -->
  7. To test the new component, add its description to the configuration file of the host emulator (<path_to_host>/Default/Entities.def).Для тестирования нового компонента добавьте его описание в конфигурационный файл эмулятора хоста (<path_to_host>/Default/Entities.def).

    Примечание
    Идентификатор компонента должен быть таким же, как тот, который указан в ig_config.xml.
    Исходный код
    entity
    {
    	name = "Be-200";
    	type = 200;
    	class = fixedwing;
            ....
            component
    	{
    		name = "water_drop";
    		id = 6;
    		def_state = 0;
    		state
    		{
    			name = "close";
    			value = 0;
    		}
    		state
    		{
    			name = "open";
    			value = 1;
    		}
    	}
    }

After launching your host application or a CIGI Host Emulator you can control your custom component by sending the corresponding packets to the IG.После запуска вашего хост-приложения или CIGI Host Emulator вы можете управлять своим настраиваемым компонентом, отправляя соответствующие пакеты в IG.

Create a Project using the IG Template and Component System

Последнее обновление: 19.12.2023
Build: ()