A*寻路算法详解

news/2024/11/8 18:32:45/

博主自制工具   翰华Box:https://hanhuabox.lanzous.com/b00zjq9uf

翰华Box - 开发日志:https://blog.csdn.net/qq_41517936/article/details/106409456

 

在我们平时打小游戏的时候,有时候会遇到一些小怪兽,这些小怪兽会自动追击我们的玩家的角色,但是,通常我们玩家的路线并不是固定的,那么这些小怪兽要如何自动绕开障碍物,走什么样的路线,才能最快地进行追击呢,答案就是A*寻路算法。

A* 算法是一种启发式搜索算法。本质上来讲,可以算作是广度优先搜索算法的改进。我们知道,广度优先搜索总能找到路径最短的最优解,因为它每次新的一轮遍历永远是离起始点最近的位置,这样,当扫描到目标点时,可以保证目标点的距离是离起点距离最近的,也就是找到了寻路的最优解。

A*算法的原理是什么呢?

我们假设有一个6*6的地图。

首先我们需要引进三个东西:OpenList,CloseList,[F=G+H]

OpenList和CloseList都是存储格子的集合,OpneList中存储的是可到达格子的集合,而CloseList中存储的是已到达的盒子。而F=G+H则是对格子价值的评估,其中G代表了从起点走到当前格子的成本,也就是走了多少步。而H代表了从当前格走到目标格子的距离。也就是不考虑障碍的情况下距离,距离目标还有多远。至于F,则是对G和H的综合评估。显然我们应该选择步数更少,距离目标更近的格子,所以F的值越小越好。

在上面的地图中,我们先把起点[1,3]放入OpenList,此时CloseList为空。

第二步,我们找出OpenList中F最小的方格,即唯一的方格[1,3]作为当前方格,并且把当且格子移除OpenList,放入CloseList表示这个格子已经到达并且检查过了。此时OpenList为空,而CloseLsist中存储着[1,3]。

第三步,我们要找出当前格上下左右可以到达的格子,看他们是否在OPenList中,如果不在,加入OpenList当中,计算出相应的G,H,F值,并把当前格子作为他们的父亲节点,

OpenList中的点:[1,2][2,3][1,4][0,3]

CloseList中的点:[1,3]

记录父亲节点有什么用呢?父亲节点记录了每一个点的来路,在我们最后确认最终路线的时候会使用到。

(以上的步骤就是我们的一次局部搜索,在后面的寻路中,我们会多次重复这个过程,直到找到终点为止。)

接下来,我们在OpenList中昭到F值最小的点([2,3]):

将[2,3]放入CloseList中,然后,我们继续找当前格子上下左右中所有可以到达的格子:

这次只增加了两个格子:[2,2][2,4],因为左边的[1,3]格子已经在CloseList中了,而右边的格子是不可以到达的墙壁。

接下来,我们要在OpenList找到当前父格子的子节点中F最小的点,因为两个点的F值相等,我们可以选择任意一个加入到CloseList中,此时

OpenList中的点:[1,2][2,3][1,4][0,3][2,2]

CloseList中的点:[1,3][2,4]

然后接下来,我们再找到当前格子上下左右所有可以到达的格子,看他们是否再OpenList中,如果不在,则加入到OpenList中计算出相应的GHF值,并把当前格子作为父亲节点:

OpenList中的点:[1,2][2,3][1,4][0,3][2,2][2,5]

CloseList中的点:[1,3][2,4]

这次只有一个点,所以我们将其放入CloseList中:

OpenList中的点:[1,2][2,3][1,4][0,3][2,2]

CloseList中的点:[1,3][2,4][2,5]

然后接下来重复刚才的步骤进行迭代,直到到达终点:

听起来不是很难,我们来看一下如何伪代码:

public Node aStarSearch(Node start, Node end) {openList.add(start);// 第一步:把起点加入 open listwhile (openList.size() > 0) { //循环,每一轮检查一个当前方格节点Node current = findMinNode();// 在OpenList中查找 F值最小的节点作为当前方格节点openList.remove(current);// 当前方格节点从open list中移除closeList.add(current);// 当前方格节点进入 close listList<Node> neighbors = findNeighbors(current);// 找到所有邻节点for (Node node : neighbors) {if (!openList.contains(node)) {//邻近节点不在OpenList中,标记父亲、G、H、F,并放入OpenListmarkAndInvolve(current, end, node);}}//如果终点在OpenList中,直接返回终点格子if (find(openList, end) != null) {return find(openList, end);}}//OpenList用尽,仍然找不到终点,说明终点不可到达,返回空return null;}

 


http://www.ppmy.cn/news/547597.html

相关文章

Hive常用函数大全(一)(关系/数学/逻辑/数值/日期/条件/字符串/集合统计/复杂类型)

测试数据集&#xff1a; create external table if not exists order_detail( user_id string, device_id string, user_type string, price double, sales int ) row format delimited fields terminated by \t lines terminated by \n stored as textfile;hdfs dfs -put /h…

在VM安装最新版Linux镜像

在VM中安装最新版Linux镜像 1.点开VM,选择创建新的虚拟机。 2.出现下图提示后&#xff0c;选择典型&#xff0c;更加快捷。然后点击下一步。 3.当出现下图提示时&#xff0c;选择镜像文件所在位置&#xff0c;点击下一步。 4.初次设置全名为Huifeng Linux&#xff0c;便于…

MATLAN图像处理之高频强调滤波(图像增强)

书中是对X拍的图片进行了增强 下面这个例子不太合适 但是也能体会到高频强调滤波的作用 % 图中可以看出 高频强调滤波在增强边缘的同时 距离原图的色度较近 %高通滤波器偏离了直流项&#xff0c;从而把图像的平均值降低到0. %一种补偿的方法是给高通滤波器加上一个偏移量。…

最详细的HIve常用函数整理及案例演示

Hive常用函数 一、测试数据集1.1 测试数据集&#xff1a;1.2 结果展示 二、常用函数2.1 关系运算2.1.1 常见关系运算符2.1.2 空值判断2.1.3 非空判断2.1.4 LIKE2.1.5 RLIKE2.1.6 REGEXP 2.2 数学运算2.2.1 - * /2.2.2 %2.2.3 位与& 位或| 位异或^ 位取反~ 2.3 逻辑运算2.3…

ubuntu20.04 磁盘故障,然后重装22.04

ubuntu20.04 磁盘故障&#xff0c;然后重装22.04 重装原因开机自启动不需要使用sudo 软件截图 flameshot输入法 fcitx5 重装原因 编译程序报错 /usr/include/x86_64-linux-gnu/bits/signum.h:26:10: fatal error: /usr/include/x86_64-linux-gnu/bits/signum-generic.h: 结构需…

基于SpringBoot+SpringCloud+vue的智慧养老平台设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

第三方库介绍——Protobuf库(更高效的协议)

文章目录 protobuf综述传输协议与指令创建协议编译协议 利用soctet实现客户端与服务端传输协议Linux&#xff08;Ubuntu&#xff09;安装protoc步骤编写案例代码 protobuf综述 Protocol Buffers&#xff0c;是Google公司开发的一种数据格式&#xff0c;类似于XML和json&#x…

【面试题09】PHP中单引号’与双引号” 区别

文章目录 一、概览二、区别2.1 双引号支持变量解析2.2 双引号支持转义符&#xff0c;单引号不支持2.3 双引号比单引号更占用内存2.4 单引号比双引号快 总结 一、概览 本文已收录于PHP全栈系列专栏&#xff1a;PHP面试专区。 计划将全覆盖PHP开发领域所有的面试题&#xff0c;对…