This page has been translated automatically.
视频教程
界面
要领
高级
实用建议
UnigineEditor
界面概述
资产工作流程
设置和首选项
项目开发
调整节点参数
Setting Up Materials
Setting Up Properties
照明
Landscape Tool
Sandworm
使用编辑器工具执行特定任务
Extending Editor Functionality
嵌入式节点类型
Nodes
Objects
Effects
Decals
光源
Geodetics
World Nodes
Sound Objects
Pathfinding Objects
Players
编程
基本原理
搭建开发环境
Usage Examples
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Plugins
File Formats
Rebuilding the Engine Tools
GUI
双精度坐标
应用程序接口
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
创建内容
Content Optimization
Materials
Art Samples
Tutorials

创建自定义组件

警告
本文介绍的功能在 Community SDK 版本中不可用。
您应该升级到 Sim SDK版本才能使用它。

You can extend the initial set of components that can be added to entities by adding custom ones. As an example let us consider adding a water drop component for the Be-200 aircraft available in the IG Template.您可以通过添加自定义组件来扩展可以添加到实体的组件的初始集合。例如,让我们考虑为IG Template中可用的Be-200飞机添加水滴组件。

Workflow工作流程#

Follow the instructions given below to create you own custom component.请按照下面给出的说明创建您自己的自定义组件。

  1. Create a new project using the IG Template and Component System as described here.使用IG Template和创建一个新项目组件系统如前所述这里

    Create a Project using the IG Template and Component System

  2. Add the following initialization code for the Component System to the AppSystemLogic::init() method in the AppSystemLogic.cpp file:将以下用于组件系统的初始化代码添加到AppSystemLogic.cpp文件中的AppSystemLogic::init()方法中:

    源代码 (C++)
    virtual int AppSystemLogic::init()
    {
    	// initialize ComponentSystem and register all components
    	Unigine::ComponentSystem::get()->initialize();
    
    	/*...*/
    	
    	return 1;
    }
  3. Create (or add) the following files describing your new component to the C++ project:创建(或添加)以下文件,以将您的新组件描述到C ++项目中:

    注意

    The component should be inherited from both the ComponentBase and the ComponentBaseInterface classes.该组件应同时从ComponentBaseComponentBaseInterface类继承。

    If you want to synchronize your component (its internal state, any parameters, commands, etc.), you can override the following methods:如果要同步组件(组件的内部状态,任何参数,命令等),则可以覆盖以下方法:

    • saveState() — for code writing component's data to be synchronized to a blob on the Master.saveState() —用于代码写入组件的数据以同步到主服务器上的Blob。
    • restoreState() — for code reading the data from the blob on Slaves.restoreState() —用于从从站的blob读取数据的代码。
    • WaterDropAircraftController.h

      源代码 (C++)
      #ifndef _WATER_DROP_AIRCRAFT_CONTROLLER_INCLUDED_
      #define _WATER_DROP_AIRCRAFT_CONTROLLER_INCLUDED_
      
      #include <UnigineGame.h>
      #include <plugins/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.h

      源代码 (C++)
      #ifndef _WATER_DROP_AIRCRAFT_CONTROLLER_INCLUDED_
      #define _WATER_DROP_AIRCRAFT_CONTROLLER_INCLUDED_
      
      #include <UnigineGame.h>
      #include <plugins/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);
      
      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();
      }

      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组件关联,这些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 UnigineEditor 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 UnigineEditor 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)。其名称和参数必须与组件的头文件中描述的名称和参数相对应(请参见第三步

    源代码 (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)的配置文件中。

    注意
    Component ID must be the same as the one specified in the ig_config.xml.组件ID必须与ig_config.xml中指定的ID相同。
    源代码
    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

最新更新: 2021-04-29
Build: ()