首页 > 其他分享 >UE4 寻路

UE4 寻路

时间:2024-04-25 23:22:21浏览次数:21  
标签:int 路径 消耗 数组 UE4 寻路 起点 dis

寻路

就是对图的遍历,目前主要处理对可转换为二维矩阵的方格图遍历

DFS 与 BFS

两种最基础的遍历方式,DFS采用回溯思想,将从起点开始沿着一个方向搜索,直到超出界限(回溯)或者到达目的地(返回结果)

//只考虑上下左右四个方向
vector<vector<pair{int,int}>> res;
vector<pair{int,int}> path;
int dir[4][2] = {-1,0,1,0,0,1,0,-1};
void dfs(vector<vector<int>>& grid,int x,int y)
{
  if(x == targetx && y == targety)
  {
    res.push_back(path);
  }
  for(int i = 0;i<4;i++)
  {
    int nextx = x + dir[i][0];
    int nexty = y + dir[i][1];
    if(nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size())
    {
      continue;
    }
    path.push_back({nextx,nexty});
    dfs(grid,nextx,nexty);
    path.pop_back();
  }
}

而BFS则是一圈一圈的搜索,从起点向终点逐渐扩展,直到下一个圈包含了终点

int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {
    queue<pair<int, int>> que;
    que.push({x, y});
    visited[x][y] = true;
    while(!que.empty()) {
        pair<int ,int> cur = que.front(); 
        que.pop(); 
        int curx = cur.first;
        int cury = cur.second; 
        for (int i = 0; i < 4; i++) {
            int nextx = curx + dir[i][0];
            int nexty = cury + dir[i][1];
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
            if (!visited[nextx][nexty]) {
                que.push({nextx, nexty});
                visited[nextx][nexty] = true;
            }
        }
    }
}

最短路寻找

在游戏中自动寻找路径一般为对最短路的寻找,当点与点之间存在距离权重时,可以考虑Dijkstra算法

Dijkstra算法

利用优先队列实现排序,降低时间复杂度。

//定义一条边,从u点到v点的权值为w
struct edge {
  int v, w;
};
//定义一个节点存储距离和当前节点
struct node {
  int dis, u;

  bool operator>(const node& a) const { return dis > a.dis; }
};

vector<edge> e[maxn];
int dis[maxn], vis[maxn];
//优先队列存储起点到当前点的dis
priority_queue<node, vector<node>, greater<node> > q;

void dijkstra(int n, int s) {
  memset(dis, 63, sizeof(dis));
  //起点为s点
  dis[s] = 0;
  q.push({0, s});
  while (!q.empty()) {
    //获取当前队列的头部
    int u = q.top().u;
    q.pop();
    //如果之前被访问过,跳过,因为现在肯定距离不是最小的
    if (vis[u]) continue;
    //置为1,说明访问过了
    vis[u] = 1;
    //对于所有与u点连通的点
    for (auto ed : e[u]) {
      int v = ed.v, w = ed.w;
      //当记录的路径大于新的路径,那么更新
      if (dis[v] > dis[u] + w) {
        dis[v] = dis[u] + w;
        q.push({dis[v], v});
      }
    }
  }
}

A*算法

(参考链接)[https://blog.csdn.net/Zhouzi_heng/article/details/115035298]
A*算法应该算作最常用的算法了。其想法是对当前点的路径排序,排序基准就是路径消耗(F) = 起点到该点的消耗(G) + 终点到该点的消耗(H)
首先需要维护两个数组,
数组1:一个为根据路径排序的数组,其存储的是从起点到终点可能走过的点,而这些点通常是下面那个数组的每个元素的可以到达的点组成的
数组2:第二个数组为最短路径数组,即结果数组,每次可以将第一个数组中的第一个元素取出放入即可。
其次就是路径排序了。可以对当前点计算路径消耗,然后利用插入排序寻找该点在数组1中的合理位置。

对于每个节点我们需要维护的是以下几个元素

  1. 当前节点位置
  2. 其父节点位置(即能到达他的最小消耗的节点)
  3. F
  4. G
  5. H

当我们找到了终点时,可以通过终点沿着存储的元素2,一直退回到起点得到路径

路径计算

起点到该点的路径消耗,由于退化为了二维数组,所以距离消耗计算就变为了横纵坐标插值(如果考虑对角线的话,还有对角线长度)
当前点到起点的消耗,就可以变为前一个点到起点的消耗 + 前一个点到当前点的消耗
对于终点到该点的消耗,一般采用估算法,首先是不考虑路径上的障碍,并且忽略通过对角线移动的情况,只考虑横纵坐标方向移动之和,然后乘以某个因子,即得到终点到起点的消耗。
最终两个消耗相加,可以得到该点的路径消耗

不断更新数组1,数组2,直到到达

当对起点周围的点计算完路径消耗后,加入到数组1中,再从数组1中取出第一个元素加入数组2中。该元素将作为下一轮路径计算的起点。
通过新元素计算G,如果该元素能到达的点已经出现在了数组1中,那么就需要进行比较,如果新G值为小值,就需要对数组1进行更新。并且改变这个已记录值的父亲。
对数组1更新主要是重新进行排序。

UE中实现

蓝图

首先需要创建一个结构体代表一个节点信息

对应了当前节点,G(第二个和第三个之和),H,父节点
同样创建两个数组1DiscoveredTileIndex以及数组2AnalysedTileIndex,分别表示搜索数组以及压入的下一个地点数组。
同时创建了一个用于排序的数组3DiscoveredTileSortingCosts
还有一个数组4结果数组

  1. 首先压入起点,并从起点开始寻找邻接点
    压入起点

    寻找某点的邻接点
    在上图中,实现的功能是寻找某点的邻接点,并且计算该邻接点的消耗(由于从上一个点到该点的消耗都为1所以忽略了),而用来估算终点到该点的消耗采用下方这个方式
    估算消耗
    数组3长度为0时,或者消耗值大于数组3的最后一个元素时,直接向数组1以及数组3队尾压入即可
    如果小于数组3的最后一个元素值,那么就需要搜索合适的位置,然后向数组1以及数组3插入。
  2. 对获得的数组1进行循环
    如果数组1的长度大于0,说明该点有可以到达的点,那么就可以计算最短路径
    首先将数组1中的第一个元素压入到数组2中,表示该点为前一个点向终点移动的最小消耗点

    然后将该最小消耗点记录,计算其的邻接点数组,对这个邻接点数组进行遍历,求解消耗,压入数组1数组3
  3. 求解邻接点消耗
    首先判断该邻接点是否已经存在数组2中,如果已经存在就可以返回
    然后根据结构体中的当前点记录的起点消耗,以及邻接点的前一个点消耗计算出邻接点的起点消耗

    如果邻接点不存在于数组1中,那么直接构造结构体,压入即可
    如果存在,那么就要从之前遍历过的路径数组4中找到旧消耗来进行比较

    然后构造结构体压入
  4. 生成路径
    倒序寻找到的路径数组,通过结构体存储的前一个节点数据值,获得路径。

标签:int,路径,消耗,数组,UE4,寻路,起点,dis
From: https://www.cnblogs.com/XTG111/p/18157356

相关文章

  • UE4纯C++实现游戏中快捷栏之创建快捷栏UI
    作为一个在游戏界面中显示的快捷栏,我们需要在游戏运行时就显示出快捷栏UI,故我们创建两个Widget。1.SlAiGameHUDWidget:负责游戏中界面UI的整体显示2.SlAiShortcutWidget:负责快捷栏部件的显示与逻辑然后我们通过:1.将GameHUDWidget添加进视口:在GameHUD文件中添加Game......
  • Unity3D 打造基于AStar的寻路与导航详解
    Unity3D打造基于AStar的寻路与导航详解BYCW丶零夜 ​关注 2人赞同了该文章前言寻路与导航是游戏开发中非常重要的一部分,它可以让游戏中的角色自动寻找到目标位置,并避开障碍物。本文将介绍如何使用Unity3D打造基于AStar算法的寻路与导航解,包括技术详......
  • "(UE4Editor.exe中)处有未经处理的异常:0xC0000005:读取位置0x0000000000000000时发生
    报错情况:使用ue4.27Slate编写Widget时想通过获取Worl(通过本地PlayerController获取)来实现“设置定时任务为在音乐结束后自动触发函数”的功能ps:定时执行函数代码 解决方法:使用GWorld替换掉通过第0号PlayerController获取世界 原因分析:(由于本人校验较少,暂做以下估计)在......
  • UE4 iOS打印出所有线程的调用栈
    在Xcode15.2中调试UE4游戏(Development包),执行btall打印出所有线程(共116个线程)的调用堆栈*thread#1,queue='com.apple.main-thread',stopreason=signalSIGSTOP*frame#0:0x00000001f9c7d178libsystem_kernel.dylib`mach_msg2_trap+8frame#1:0x00000001f......
  • UE4 c++ 通过枚举寻找DataTable中的数据
    DataTable中的数据DataTable中每一行数据是一个结构体在C++代码中定义结构体,然后可以在蓝图中可以创建以此结构体为单元的DataTable枚举变量定义一个头文件来存储枚举变量,然后可以在要使用的文件中利用MyEnumPtr=FindObject<UEnum>(ANY_PACKAGE,TEXT("EGridShapEnum"),tr......
  • A*寻路
    A*寻路算法在开始节点寻找四周节点,然后计算每个节点到终点需要走的步数,优先从最少的步数的节点开始走每个节点都记录是如何过来的,在最后找到终点后反向获取整个路程效果:packagetest;importjava.util.*;importjava.util.stream.Collectors;/***@authorJame!*......
  • UE4 C++ Widget的NativeConstruct 与 NativePreConstruct
    构造函数由于Widget是由UE的反射系统创建的,其生命周期由UE引擎管理,所以并不存在构造函数,UE为Widget类定义了两个虚函数NativeConstruct与NativePreConstruct来充当构造函数的作用。而这两个函数的调用都必须在Widget被实例化之后才能进行调用如何在Widget中获取角色在蓝图节......
  • UE4 存档
    基本目标:存档按键TAB保存P键显示读档界面读档后位置重置到读档内容存档界面关于每一条信息的变量和读取按钮点击事件存档存档主要的逻辑是存到内存中并存到本地显示的就是内存中的打开关卡时加载本地到内存其实整个保存的目前只是一个Location,应该封装成对象比较好,......
  • UE4.27, 代码实践, 资源加载 FSoftClassPath / FSoftObjectPath
    //以下的FSoftClassPath/FSoftObjectPath都公开在Editor里设定 //iteminTArray<FSoftClassPath>FSoftClassPathtemp=FSoftClassPath_UsedInBluePrint_BuildFunc(item);UClass*LoadedClass=temp.TryLoadClass<AActor>();FSoftClassPathFSoftClassPath_UsedInBlu......
  • UE4 UI
    2DUI点击后控制权切换制作2DUIDesignerGraph在关卡蓝图/控制器类中使用UI【一般是控制器类】效果暂停游戏制作UI暂停游戏点击事件增添UI动画3DUI全自动/半自动制作UI添加点击事件制作UI蓝图类并连接到UI上增加WidgetInteraction设置一个对外的......