This page has been translated automatically.
视频教程
界面
要领
高级
实用建议
专业(SIM)
UnigineEditor
界面概述
资源工作流程
版本控制
设置和首选项
项目开发
调整节点参数
Setting Up Materials
设置属性
照明
Sandworm
使用编辑器工具执行特定任务
如何擴展編輯器功能
嵌入式节点类型
Nodes
Objects
Effects
Decals
光源
Geodetics
World Nodes
Sound Objects
Pathfinding Objects
Players
编程
基本原理
搭建开发环境
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Plugins
File Formats
材质和着色器
Rebuilding the Engine Tools
GUI
双精度坐标
应用程序接口
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
Tutorials

在有障碍物的导航区域内创建2D路线

The example guides you through the process of setting up a scene with a simple navigation area and calculating a 2D route within it.该示例指导您通过设置一个简单的导航区域和计算其中的2D路线场景的过程。

Preparing Scene
准备场景#

Before calculating routes, we should create a navigation area within which this logic will be executed. Our navigation area will be represented by a single navigation sector with obstacles. Also, we will add some auxiliary nodes that will serve as the start and destination points of the route.在计算路由之前,我们应该创建一个导航区域,在其中执行此逻辑。我们的导航区域将由带有障碍物的单一导航扇区表示。此外,我们将添加一些辅助节点,它们将作为路线的起点和终点。

  1. Create an empty project via SDK Browser.通过SDK浏览器创建一个空项目。
  2. Open it in UnigineEditor and remove the unnecessary default nodes.在UnigineEditor中打开它并删除不必要的默认节点。
  3. In the Menu bar, choose Create -> Navigation -> Navigation Sector and place the node above the plane.在菜单栏中,选择Create -> Navigation -> Navigation Sector并将节点放在平面上方。

    注意
    To facilitate working with the navigation sectors, activate gizmos for Navigation nodes in the Helpers Panel.为了方便使用导航扇区,请在Helpers面板中为Navigation节点激活小控件。

  4. Adjust the Size of the sector in the Parameters window.Parameters窗口中调整扇区的Size

  5. Add 2 nodes that will be used as the start and destination points of the route. We will create 2 boxes (Create -> Primitives -> Box), rename them start and finish, and place inside the navigation sector as pictured below.添加两个节点,这些节点将用作路由的起点和终点。 我们将创建两个立方体(Create -> Primitives -> Box),将它们重命名为startfinish,并放置在导航扇区内,如下图所示。

  6. Create several primitives and place them inside the navigation area. We will add a capsule and two boxes.创建几个图元并将它们放置在导航区域内。 我们将添加一个胶囊和两个立方体。

  7. Make them dynamic: switch from Immovable to Dynamic in the Parameters window.使它们动态:在Parameters窗口中从Immovable切换到Dynamic

  8. For each primitive, create an obstacle of the required type: in the World Hierarchy window, right-click the primitive, choose Create -> Navigation, and select the obstacle. The created obstacle will be added as a child to the primitive node in the hierarchy.对于每个图元,创建所需类型的障碍:在World Hierarchy窗口中,右键单击该图元,选择Create -> Navigation,然后选择障碍。 创建的障碍将作为子节点添加到层次结构中的原始节点。

    注意
    It will allow you to change the node and obstacle transformations at the same time without any extra configuration.它将允许您在同一时间更改节点和障碍转换,而无需任何额外的配置。

  9. Adjust the size of the created obstacles in the Parameters window if necessary.必要时在Parameters窗口中调整创建的障碍物的大小。

Creating Component for Route Calculation
为路径计算创建组件#

The created navigation sector only provides the area within which routes are calculated. The routes themselves must be created from the code. So, let's create the corresponding C++ component for 2D route calculation.创建的导航扇区仅提供计算路线的区域。 路由本身必须从代码创建。 因此,让我们为2D路由计算创建相应的C++组件。

Add a new Route2D class inherited from the ComponentBase class (the *.h and *.cpp files) to the project. The class name will be used as the property name.将从ComponentBase类(*.h*.cpp文件)继承的新Route2D类添加到项目中。 类名将用作属性名。

Implementing Component Logic
实现组件逻辑#

  1. In the Route2D.h file, declare a component class, parameters and a route:Route2D.h文件中,声明一个组件类、参数和一个路由:

    • Two parameters that will accept nodes between which a route should be calculated.两个参数将接受应该计算路由的节点
    • Route color.路线颜色
    源代码 (C++)
    #include <UnigineComponentSystem.h>
    #include <UniginePathFinding.h>
    
    using namespace Unigine;
    using namespace Math;
    
    // derive the component from the ComponentBase class
    class Route2D : public ComponentBase
    {
    public:
    
    	// declare constructor and destructor and define a property name. The Route2D.prop file containing all parameters listed below will be saved in your project's data folder
    	COMPONENT_DEFINE(Route2D, ComponentBase);
    	// declare methods to be called at the corresponding stages of the execution sequence
    	COMPONENT_INIT(init);
    	COMPONENT_UPDATE(update);
    	COMPONENT_SHUTDOWN(shutdown);
    
    	// declare parameters of the component
    	PROP_PARAM(Node, startPoint, NULL);
    	PROP_PARAM(Node, finishPoint, NULL);
    	PROP_PARAM(Color, routeColor, vec4_zero);
    
    	void init();
    	void update();
    	void shutdown();
    
    private:
    	// declare a route
    	PathRoutePtr route;
    };
  2. In the Route2D.cpp file, register the component.Route2D.cpp文件中,注册组件。

    源代码 (C++)
    #include "Route2D.h"
    
    REGISTER_COMPONENT(Route2D);
  3. Create a route and set the radius and height for the point which will move along the route in the init() method. Before creation, check if the nodes to be used as the start and finish points are specified.init()方法中创建一条路线并设置将沿着路线移动的点的半径和高度。 在创建之前,检查是否指定了要用作起点和终点的节点。

    源代码 (C++)
    #include "Route2D.h"
    #include <UnigineNode.h>
    #include <UnigineConsole.h>
    #include <UnigineVisualizer.h>
    #include <UnigineLog.h>
    
    REGISTER_COMPONENT(Route2D);
    
    void Route2D::init() {
    	// check if the start and destination nodes are correctly specified via the component interface
    	if (startPoint && finishPoint)
    	{
    		// create a new route
    		route = PathRoute::create();
    
    		// set a radius and height for the point which will move along the route
    		route->setRadius(0.1f);
    		route->setHeight(0.1f);
    	}
    }
  4. To enable displaying the calculated route at run time, turn on the Visualizer. Additionally, you can output console messages to the application screen. Add the following logic to the init() function:要启用在运行时显示计算的路由,请打开Visualizer。 此外,您还可以将控制台消息输出到应用程序屏幕。 将以下逻辑添加到init()函数中:

    源代码 (C++)
    Console::setOnscreen(true);
    Visualizer::setEnabled(true);
  5. In the update() function, calculate the route from the start to destination node:update()函数中,计算从开始到目的节点的路由:

    源代码 (C++)
    void Route2D::update() {
    
    	if (startPoint && finishPoint)
    	{
    		route->create2D(startPoint->getWorldPosition(), finishPoint->getWorldPosition());
    		if (route->isReached())
    		{
    			// if the destination point is reached, render the root in a specified color
    			route->renderVisualizer(routeColor);
    		}
    		else
    			Log::message("PathRoute not reached yet\n");
    	}
    }
    注意
    Here the route is recalculated each frame. However, it is not optimal for application performance. Instead, you can calculate the route once per several frames: pass a delay to the create2D() function as the third argument.这里每帧重新计算路由。然而,这并不是应用程序性能的最佳选择。相反,您可以每几帧计算一次路由:将延迟传递给Create2D()函数作为第三个参数。
  6. Implement the shutdown() function to disable the Visualizer and onscreen console messages:实现shutdown()函数以禁用Visualizer和屏幕上的控制台消息:

    源代码 (C++)
    void Route2D::shutdown() {
    
    	Console::setOnscreen(false);
    	Visualizer::setEnabled(false);
    }
  7. The component is registered automatically by the Component System upon its initialization. However, you should add the following to the AppSystemLogic::init() method:组件在初始化时由组件系统自动注册。 但是,您应该将以下内容添加到AppSystemLogic::init()方法中:

    源代码 (C++)
    #include <UnigineComponentSystem.h>
    
    int AppSystemLogic::init() {
    	// initialize ComponentSystem and register components
    	Unigine::ComponentSystem::get()->initialize();
    
    	return 1;
    }
  8. Build the project and run it once to generate the property for the Route2D component. It will be located in the data/ComponentSystem folder.构建项目并运行一次以生成Route2D组件的属性。 它将位于data/ComponentSystem文件夹中。

Here is the full code of the component:下面是组件的完整代码:

源代码 (C++)
#pragma once

#include <UnigineComponentSystem.h>
#include <UniginePathFinding.h>

using namespace Unigine;
using namespace Math;

// derive the component from the ComponentBase class
class Route2D : public ComponentBase
{
public:

	// declare constructor and destructor and define a property name. The Route2D.prop file containing all parameters listed below will be saved in your project's data folder
	COMPONENT_DEFINE(Route2D, ComponentBase);
	// declare methods to be called at the corresponding stages of the execution sequence
	COMPONENT_INIT(init);
	COMPONENT_UPDATE(update);
	COMPONENT_SHUTDOWN(shutdown);

	// declare parameters of the component
	PROP_PARAM(Node, startPoint, NULL);
	PROP_PARAM(Node, finishPoint, NULL);
	PROP_PARAM(Color, routeColor, vec4_zero);

	void init();
	void update();
	void shutdown();

private:
	// a route
	PathRoutePtr route;
};
源代码 (C++)
#include "Route2D.h"
#include <UnigineNode.h>
#include <UnigineConsole.h>
#include <UnigineVisualizer.h>
#include <UnigineLog.h>

REGISTER_COMPONENT(Route2D);

void Route2D::init() {
	// check if the start and destination nodes are correctly specified via the component interface
	if (startPoint && finishPoint)
	{
		// create a new route
		route = PathRoute::create();

		// set a radius and height for the point which will move along the route
		route->setRadius(0.1f);
		route->setHeight(0.1f);

		Console::setOnscreen(true);
		Visualizer::setEnabled(true);
	}
}

void Route2D::update() {

	if (startPoint && finishPoint)
	{
		route->create2D(startPoint->getWorldPosition(), finishPoint->getWorldPosition());
		if (route->isReached())
		{
			// if the destination point is reached, render the root in a specified color
			route->renderVisualizer(routeColor);
		}
		else
			Log::message("PathRoute not reached yet\n");
	}
}

void Route2D::shutdown() {
	
	Console::setOnscreen(false);
	Visualizer::setEnabled(false);
}

Assigning Component
分配组件#

When the component logic is implemented and the property is generated, you should assign it to a node.当实现组件逻辑并生成属性时,您应该将其分配给一个节点。

  1. In UnigineEditor, select Create -> Node -> Dummy and place it in the navigation area.在UnigineEditor中,选择Create -> Node -> Dummy并将其放置在导航区域中。
  2. Select the dummy node and assign the Route2D property to it in the Parameters window.选择虚拟节点并在Parameters窗口中为其分配Route2D属性。
  3. In the component parameters, specify the start and finish static meshes in the Start Point and Finish Point fields.在组件参数中,在Start PointFinish Point字段中指定startfinish静态网格体。

  4. Change the Route Color, if necessary.如有必要,请更改Route Color

Making Obstacles Move Dynamically
使障碍物动态移动#

Let's add a bit of complexity to the logic and make the nodes that are used as obstacles dynamically change.让我们为逻辑添加一点复杂性,并使用作障碍的节点动态变化。

  1. Add a new NodeRotator class inherited from the ComponentBase class (the *.h and *.cpp files) to the project.将从ComponentBase类(*.h*.cpp文件)继承的新NodeRotator类添加到项目中。
  2. Implement rotation logic:实现旋转逻辑:

    源代码 (C++)
    #include <UnigineComponentSystem.h>
    
    using namespace Unigine;
    using namespace Math;
    
    class NodeRotator : public ComponentBase
    {
    
    public:
    	COMPONENT_DEFINE(NodeRotator, ComponentBase);
    	COMPONENT_UPDATE(update);
    
    	// declare a parameter of the component
    	PROP_PARAM(Vec3, angularVelocity, vec3_zero);
    
    	void update();
    };
    源代码 (C++)
    #include "NodeRotator.h"
    
    #include <UnigineGame.h>
    
    REGISTER_COMPONENT(NodeRotator);
    
    void NodeRotator::update()
    {
    	// calculate the delta of rotation
    	vec3 delta = angularVelocity * Game::getIFps();
    	// update node rotation
    	node->setRotation(node->getRotation() * quat(delta.x, delta.y, delta.z));
    }
  3. Build the project and run it once again to generate the property for the NodeRotator component.构建项目并再次运行它以生成NodeRotator组件的属性。
  4. Assign the component to the capsule primitive that should rotate and specify the Angular Velocity:将组件分配给应旋转的capsule基元并指定Angular Velocity:

    The obstacle will rotate as well.障碍物也会旋转。

  5. Group the sphere primitives and assign the component to the parent dummy node. It will make the spheres rotate around this parent node (as in the case of a sphere, rotation around its own axis won't affect the route calculation).sphere基元进行分组,并将组件分配给父虚节点。 它将使球体围绕此父节点旋转(就像球体的情况一样,围绕其自己的轴旋转不会影响路线计算)。

Visualizing Navigation Area
可视化导航区域#

To clearly show how the path is built inside the navigation area, let's implement the AreaVisualizer component that enables displaying the navigation area gizmo at run time:为了清楚地显示路径是如何在导航区域内构建的,让我们实现AreaVisualizer组件,该组件允许在运行时显示导航区域小工具:

  1. Add a new AreaVisualizer class inherited from the ComponentBase class (the *.h and *.cpp files) to the project.将从ComponentBase类(*.h*.cpp文件)继承的新AreaVisualizer类添加到项目中。
  2. Implement the logic:实现逻辑:

    源代码 (C++)
    #pragma once
    #include <UnigineComponentSystem.h>
    #include <UniginePathFinding.h>
    
    using namespace Unigine;
    
    class AreaVisualizer : public ComponentBase
    {
    public:
    	COMPONENT_DEFINE(AreaVisualizer, ComponentBase);
    	COMPONENT_UPDATE(update);
    
    	void update();
    };
    源代码 (C++)
    #include "AreaVisualizer.h"
    
    #include <UnigineVisualizer.h>
    
    REGISTER_COMPONENT(AreaVisualizer);
    
    void AreaVisualizer::update()
    {
    	// display the navigation area gizmo
    	node->renderVisualizer();
    }
  3. Build the project and run it once again to generate the property for the AreaVisualizer component.构建项目并再次运行它以生成AreaVisualizer组件的属性。
  4. Assign the component to the navigation sector.将组件分配给导航扇区。

Trying Out
尝试#

Launch the application to check the result.启动应用程序以检查结果。

最新更新: 2024-05-28
Build: ()