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
统一的Unigine着色器语言 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
注意! 这个版本的文档是过时的,因为它描述了一个较老的SDK版本!请切换到最新SDK版本的文档。
注意! 这个版本的文档描述了一个不再受支持的旧SDK版本!请升级到最新的SDK版本。

在连接的导航扇区内创建路线

The example guides you through the process of setting up a scene with a navigation area of a complex form and calculating 2D and 3D routes within it.该示例指导您通过设置具有复杂形式的导航区域的场景并在其中计算2D和3D路线的过程。

In UNIGINE, only Navigation Sectors can be used for calculation of both 2D and 3D routes. The navigation sectors can be easily rearranged, disabled, or enabled on the fly. Moreover, you can specify the sectors that can participate in pathfinding and exclude others. In order to form a unified navigation area, the sectors must intersect with each other.在UNIGINE中,只有Navigation Sector可用于2D和3D路线的计算。 导航扇区可以很容易地重新排列、禁用或启用。 此外,您可以指定参与寻路的扇区,并排除其他扇区。为了形成统一的导航区域,扇区之间必须相互相交。

Let's consider these features in detail.让我们详细分析这些特性。

Preparing Scene
准备场景#

Our scene will include a navigation area that consists of multiple intersecting navigation sectors and primitives indicating the start and destination points of a route.我们的场景将包括一个导航区域,该区域由多个相交的导航扇区和指示路线起点和目的地点的图元组成。

  1. Create an empty C# project via SDK Browser.通过SDK Browser创建一个空的C#项目
  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. Add 8 more navigation sectors to the scene by cloning (Ctrl+D) the existing sector and place them as follows:通过克隆(Ctrl+D)现有扇区,在场景中添加8个导航扇区,并将其放置如下:

    注意
    You can position the sectors manually using manipulators or by specifying the exact position via the Parameters window.您可以使用操纵器或通过Parameters窗口指定精确位置手动定位扇区。

  5. In the Parameters window, adjust the positions of the nodes along the Z axis so that they are all positioned at the same level above the plane.Parameters窗口中,沿Z轴调整节点的位置,使它们都位于平面上方的同一水平。
  6. Add a new sector and adjust its Size in the Parameters window to give it a parallelepiped shape.添加一个新扇区并在Parameters窗口中调整其Size,使其具有平行六面体形状。

    注意
    At this step, you can approximately set the size of the sector. However, you may need to adjust it later to prevent excluding the navigation sector from pathfinding.在这一步,可以近似地设置扇区的大小。 但是,您可能需要稍后进行调整,以防止将导航扇区排除在寻路之外。
  7. Connect the cuboid-shaped navigation sectors: place the new sector between them.连接长方体形状的导航扇区:将新扇区置于它们之间。

    注意
    For 2D routes, the height difference between the intersecting sectors must not exceed the maximum height set for the 2D route; otherwise, these sectors are discarded from pathfinding. In addition, the intersection area must exceed the radius and height of the route. So, it may be necessary to adjust the size and position of the sector to correct the intersection area.对于2D路由,相交扇区之间的高度差不得超过为2D路由设置的最大高度;否则,从寻路中丢弃这些扇区。 此外,交叉区域必须超过路线的半径和高度。 因此,可能需要调整扇区的大小和位置以校正相交区域。
  8. Add 11 more navigation sectors that connect the cuboid-shaped sectors by cloning (Ctrl+D) the existing sector and place them as follows:通过克隆(Ctrl+D)现有扇区,再添加11个连接长方体形状扇区的导航扇区,并将其放置如下:

  9. Organize the created navigation sectors in a hierarchy. It will allow you to manage the navigation area as a single node. Select all the navigation sectors, right-click, and choose Group in the drop-down list or press Ctrl+G.在层次结构中组织创建的导航扇区。 它将允许您将导航区域管理为单个节点。 选择所有导航扇区,右键单击,并在下拉列表中选择Group或按Ctrl+G

  10. Add 2 nodes to 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 then place them inside the navigation sector as pictured below.添加2个节点用作路由的起点和终点。 我们将创建2个平行六面体(Create -> Primitives -> Box),将它们重命名为startfinish,然后将它们放置在导航扇区中,如下图所示。

Creating Component for 2D Route Calculation
创建用于2D路径计算的组件#

The created navigation sectors only provide 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++组件。

注意
If you have completed the previous guide on creating routes within a simple navigation sector, you can skip this step and copy the implemented Route2D component to the source folder of your project (both the *.h and *.cpp files).如果您已完成上一篇关于在简单导航扇区中创建路由的指南,则可以跳过此步骤并将实现的Route2D组件复制到项目的source文件夹(*.h*.cpp文件)。

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
实现组件逻辑#

注意
If you have copied the Route2D component on the previous step, you can skip this one.如果您在上一步复制了Route2D组件,则可以跳过此步骤。
  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()函数以禁用可视化工具和屏幕控制台消息:

    源代码 (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

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 each navigation sector forming the navigation area.将组件分配给形成导航区域的每个导航扇区。

Trying Out
尝试#

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

注意
If the route is not reached, try to modify the route parameters (a point height and/or radius) or adjust the size of the sector(s) or intersection area(s), as the point moving along the route must fit the size of the navigation area.如果未到达路线,请尝试修改路线参数(点高度和/或半径)或调整扇区或交叉区域的大小,因为沿着路线移动的点必须适合导航区域的大小。

Excluding Sectors from Pathfinding
从寻路中排除扇区#

Sometimes, it might be necessary to ignore some navigation sectors during pathfinding. For this purpose, you can set the Navigation mask for both the navigation sector and the route so that they don't match.有时,可能需要在寻路过程中忽略某些导航扇区。 为此,您可以为导航扇区和路线设置Navigation掩码,以便它们不匹配。

  1. Select one of the navigation sectors participating in pathfinding.选择参与寻路的导航扇区之一。

  2. Change its Navigation Mask in the Parameters window.Parameters窗口中更改其Navigation Mask

  3. Run the application to check how the route is recalculated.运行应用程序以检查路由是如何重新计算的。

Modifying Component for 3D Route Calculation
修改三维路径计算组件#

The navigation sector also enables the calculation of 3D routes, with some features that differ from the 2D routes:导航部分还可以计算3D路线,具有与2D路线不同的一些特征:

  • For 3D routes, the point moves in 3 dimensions.对于3D路线,点在3维中移动。
  • Only the radius set for the point matters: if the radius set for the point is greater than the size of the navigation sector, it will be discarded.只有为点设置的半径才重要:如果为点设置的半径大于导航扇区的大小,它将被丢弃。
  • The maximum height set for the route determines the upper limit of the point's vertical movement.为路线设置的最大高度确定点垂直移动的上限。

You can force the Route2D component to calculate a 3D route within the same navigation area by changing a single line of the code. Replace the create2D() function call with the following:您可以通过更改代码的单行来强制Route2D组件计算同一导航区域内的3D路线。 将create2D()函数调用替换为以下内容:

源代码 (C#)
route->create3D(startPoint->getWorldPosition(), finishPoint->getWorldPosition());

Then build the project and run it once again to re-generate the property for the Route2D component.然后构建项目并再次运行它以重新生成Route2D组件的属性。

Run the application to check the result.运行应用程序以检查结果。

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