unity3d:Astar寻路,A星,A*,二叉堆优化Open表

2023-05-16

原理视频

油管:https://youtu.be/i0x5fj4PqP4
别人的B站翻译:https://www.bilibili.com/video/BV1v44y1h7Dt?spm_id_from=333.999.0.0

基本概念

3个数值

G:起点到当前点步数:会随着路径的改变,例如找到一条更好的路了,A的点G = 原本A的G 和 cur路径到A的G(cur的G + cur到A的G)中的最小值
在这里插入图片描述

H:当前点到终点步数,乐观估计,无视障碍物。即实际的H(包含绕开障碍物的整条代价) > 按照无障碍物走的最短H
在这里插入图片描述

F:G+H
就是每一步都找最小F的走

每步移动代价

在这里插入图片描述
在这里插入图片描述

方便计算 * 10
在这里插入图片描述

Open表与Close表

var listOpen = new List() { startNode }; //开放集合,可以进行计算(但没有被选中)的节点 ,将初始节点加入到OpenSet当中。所有可能,每走一步都要放入
var listClose = new List();//封闭集合,所有已经计算过而且也被算中的节点 。表示改点已经走过,且是代价最小的点

伪代码

https://blog.csdn.net/a591243801/article/details/80655416

Init
得到StartNode与TargetNode

初始化OpenSet与CloseSet
    将初始节点加入到OpenSet当中

Loop (OpenSet.Count > 0)
//找出OpenSet当中fCost最小的点,这个点就是被选中的将要行走的下一个点
currentNode = OpenSet当中fCost最小的点

//将这个点从OpenSet当中移除
OpenSet.Remove(currentNode);
//将这个点加入到ClostSet当中
ClosrSet.Add(currentNode);

if(currentNode == targetNode)
    路径已经找到

//若路径没有找到,则查找当前选中的节点的邻居节点,
//计算他们的fCost并加入到OpenSet当中方便下一轮计算
foreach neighbour of the currentNode
    //若这个节点是不可以行走,或者已经被算中过了,则跳过这个节点
    if (!neighbour.walkable || closeSet.Contains(neighbour))
        continue;

    //计算这个这个邻居节点的gCost,若gCost更小则说明
    //通过currentNode到这个节点的距离更加的短(代价更小)
    newGCostToNeighbour = currentNode.gCost + 
                    GetDistance(currentNode,neighbour);

    //gCost若更小的话则需要重新计算这个点的fCost和他的父亲节点
    //若这个节点不在OpenSet的话,则计算这个节点的fCost与设置父亲节点
    //通过设置父亲节点,那么在之后找到路径之后可以通过父亲节点找到整条路径
    if(newGCostToNeighbour < neighbour.gCost || 
                    !openSet.Contans(neighbour)){

        neighour.fCost = evaluateFCost(neighour);
        neighour.parentNode = currentNode;

        if(!OpenSet.Contains(neighour)){
            OpenSet.Add(neighbour);
        }
    }

核心代码

节点

 public abstract class NodeBase : MonoBehaviour {
         public List<NodeBase> Neighbors { get; protected set; }//周围的邻居
        public NodeBase Connection { get; private set; }//上一个节点
        public float G { get; private set; } //起点到当前:每次找邻居会更新, 取当前到这个邻居,和原本设定中的最小
        public float H { get; private set; }//当前到达终点:乐观估计,会绕过障碍物,可能比真实到达的要小
        public float F => G + H; //两者之和

寻路

public static List<NodeBase> FindPath(NodeBase startNode, NodeBase targetNode) {
            var listOpen = new List<NodeBase>() { startNode }; //开放集合,可以进行计算(但没有被选中)的节点 ,将初始节点加入到OpenSet当中。所有可能,每走一步都要放入
            var listClose = new List<NodeBase>();//封闭集合,所有已经计算过而且也被算中的节点 。表示改点已经走过,且是代价最小的点

            while (listOpen.Any()) {

                //找到最小F todo:优化,每次节点多
                var current = listOpen[0];

                //找出OpenSet当中fCost最小的点,这个点就是被选中的将要行走的下一个点,如果F总和相同,找H最小,即到达终点最快(H是乐观估计,不算障碍物估计)
                foreach (var t in listOpen) 
                    if (t.F < current.F || ( t.F == current.F && t.H < current.H)) current = t;

                //将这个点从OpenSet当中移除
                listOpen.Remove(current);

                //将这个点加入到ClostSet当中
                listClose.Add(current);
                
                
                current.SetColor(ClosedColor);

                //路径已经到了
                if (current == targetNode)
                {
                    var currentPathTile = targetNode;
                    var path = new List<NodeBase>();
                    //var count = 100;
                    while (currentPathTile != startNode) {
                        path.Add(currentPathTile);
                        currentPathTile = currentPathTile.Connection; //cur的上一个连接点
                        //count--;
                        //if (count < 0) throw new Exception();
                        //Debug.Log("sdfsdf");
                    }
                    
                    foreach (var tile in path) tile.SetColor(PathColor);
                    startNode.SetColor(PathColor);
                    Debug.Log(path.Count);
                    return path;
                }

                //找curNode的邻居,可到达和未在close表(即已经算过的不会再进行计算)
                foreach (var neighbor in current.Neighbors.Where(t => t.Walkable && !listClose.Contains(t))) {
                    //是否未计算过这个邻居
                    var inSearch = listOpen.Contains(neighbor);
                    //从cur到邻居的G = curG+cur到邻居的G代价
                    var costToNeighbor = current.G + current.GetDistance(neighbor);

                    //路径发生改变,g会变化,例如找到一条更好的路
                    if (!inSearch || costToNeighbor < neighbor.G) {
                        neighbor.SetG(costToNeighbor);
                        neighbor.SetConnection(current);
                        
                        //h是乐观估计,只需要算一遍
                        if (!inSearch) {
                            neighbor.SetH(neighbor.GetDistance(targetNode));
                            listOpen.Add(neighbor);
                            neighbor.SetColor(OpenColor);
                        }
                    }
                }
            }
            return null;
        }

优化

Open表用二叉堆

二叉堆原理
https://www.cnblogs.com/alimayun/p/12779640.html
父节点就是下标为i/2的节点。
插入节点(按照小堆为例子)

  1. 插入到最后一个位置,元素为a
  2. a跟父节点b比,如果插入的a更小,上浮,ab交换位置
    删除节点
  3. 删除的是头节点
  4. 把最后一个临时a补到堆顶
  5. 跟左b右c比较,如果a比bc中最小的还小,a与其一换位置,为下沉操作
using System;
using System.Collections.Generic;
using System.Text;

namespace DataStructure
{
    public enum HeapType
    {
        MinHeap,
        MaxHeap
    }

    public class BinaryHeap<T> where T : IComparable<T>
    {
        public List<T> items;

        public HeapType HType { get; private set; }

        public T Root
        {
            get { return items[0]; }
        }

        public BinaryHeap(HeapType type)
        {
            items = new List<T>();
            this.HType = type;
        }

        public bool Contains(T data)
        {
            return items.Contains(data);
        }

        

        public void Push(T item)
        {
            items.Add(item);

            int i = items.Count - 1;

            bool flag = HType == HeapType.MinHeap;

            while (i > 0)
            {
                if ((items[i].CompareTo(items[(i - 1) / 2]) > 0) ^ flag)
                {
                    T temp = items[i];
                    items[i] = items[(i - 1) / 2];
                    items[(i - 1) / 2] = temp;
                    i = (i - 1) / 2;
                }
                else
                    break;
            }
        }

        private void DeleteRoot()
        {
            int i = items.Count - 1;

            items[0] = items[i];
            items.RemoveAt(i);

            i = 0;

            bool flag = HType == HeapType.MinHeap;

            while (true)
            {
                int leftInd = 2 * i + 1;
                int rightInd = 2 * i + 2;
                int largest = i;

                if (leftInd < items.Count)
                {
                    if ((items[leftInd].CompareTo(items[largest]) > 0) ^ flag)
                        largest = leftInd;
                }

                if (rightInd < items.Count)
                {
                    if ((items[rightInd].CompareTo(items[largest]) > 0) ^ flag)
                        largest = rightInd;
                }

                if (largest != i)
                {
                    T temp = items[largest];
                    items[largest] = items[i];
                    items[i] = temp;
                    i = largest;
                }
                else
                    break;
            }
        }

        public T PopRoot()
        {
            T result = items[0];

            DeleteRoot();

            return result;
        }
    }

}

源码

https://github.com/luoyikun/UnityForTest
AStarDemo场景

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

unity3d:Astar寻路,A星,A*,二叉堆优化Open表 的相关文章

  • Unity Cinemachine插件学习笔记,实现单目标和多目标之间切换

    Cinemachine在2017版中正式加入 结合Timeline可以轻松的制作出一下相机动画 相比Unity自带的标准相机 这个Cinemachine插件可操作的变量更多 不同虚拟相机 用来控制相机的 可以平滑转换等 具体可以参考上篇 U
  • 服务器时间管理器

    时间戳管理器 using System using UnityEngine public class SyncTime Singleton
  • 离散仿真引擎基础作业与练习

    作业内容 一 简答题 1 解释 GameObjects 和 Assets 的区别与联系 2 下载几个游戏案例 分别总结资源 对象组织的结构 3 使用 debug 验证 MonoBehaviour 基本行为或事件触发条件 4 了解 GameO
  • unity3d实现简单的打飞碟游戏

    游戏内容 游戏有n个round 每个round发射10次trial 每个trial的飞碟都可能不同 包括速度角度得分等 使用鼠标进行射击 点中即表示射击成功 游戏要求 使用带缓存的工厂模式来管理飞碟的生产与再利用 工厂使用单例模式 游戏的设
  • Unity+Pico 手柄按键控制

    一 定义手柄按键API 1 InputDevices GetDeviceAtXRNode 通过XRNode获取对应的设备 2 XRNode是一个枚举类型 包含LeftEye RightEye CenterEye Head LeftHand
  • protobuf C#编译

    protobuf C 编译 标签 protobufc 2016 08 30 23 22 342人阅读 评论 1 收藏 举报 分类 工作记录 2 版权声明 本文为博主原创文章 未经博主允许不得转载 1 下载protobuf代码 https g
  • untiy的纹理格式介绍

    Desktop RGB Compressed DXT1 压缩的RGB纹理 这是最常见的漫反射纹理格式 4位 像素 32 KB 256x256 RGBA Compressed DXT5 压缩的RGBA纹理 这是漫反射和高光控制纹理的主要格式
  • Unity编辑器扩展——进度条显示通用方法

    在我们使用Unity编辑器扩展做一些批处理的工具时 通常会需要显示一个进度条 这样不会让Unity一直卡住不动 使得使用者不知道当前的进展 那么如何显示进度条呢 涉及的相关API有 EditorUtility ClearProgressBa
  • 【Unity-学习-021】异步实现HTTP请求

    对Http访问操作 Unity中一般使用协程操作 但是协程有一个比较要命的要求就是所在Mono必须在场景中是激活的 所以一些操作就会被限制 所以我们就找办法替代掉协程做一些异步的操作 那就用异步方法 首先扩展一下AsyncOperation
  • 【Unity灯光与渲染技术】Global Illumination全局光照

    本系列主要参考Unity灯光与渲染技术教程Unity Lighting And Rendering 同时会加上一点个人实践过程和理解 分割线 这篇文章主要讲全局光照 在看教程的时候就有一个点不是很理解 就是作者开启物体的static这个选项
  • Unity3D如何修改Button显示的文字以及深入了解Button组件

    在创建了一个Button后 结构如图 先仔细观察一下Button的Inspector视图 发现其中竟然有一个叫Button的脚本组件 新建脚本 代码如下 并将该脚本绑定给Canvas组件 using UnityEngine UI using
  • [3dsMax]2018版下拉菜单项的子菜单无法选中

    软件自身问题 安装更新补丁即可解决 不想更新补丁也可以使用键盘的方向键进行选中 补丁百度云链接 https pan baidu com s 1LDxRFwQnR0GSONuz7wcEfA 提取码 6gpk
  • Unity3D:按键生成物件,Instantia…

    在按下按键之后 可以在画面中生成之前定义好了的物体 这里使用了Instantiate函数来生成 1 先在游戏中定一个空物件GameObject 创建空物件快捷键 ctrl shift n 2 在视图中放置 3 编写脚本 脚本 SpaceCh
  • Unity3d获得android和ios设备的唯一标识

    android为mac地址 ios为advertisingIdentifier 函数都比较简单 网上也搜得到 我也就不多说了 主要是对于我们没做过安卓和IOS开发的人来说 整合进工程有各种的问题 我也就直接上网盘了点击打开链接 代码包里看得
  • java中Keytool的使用总结

    java中Keytool的使用总结 2011 02 26 15 30 15 分类 在申请Android Map API Key的时候使用到了java中Keytool 下面转一篇介绍java中Keytool的文章 http blog csdn
  • 寻找 A* 算法的启发式有哪些好方法?

    您有一张方形图块地图 您可以在其中向 8 个方向中的任意方向移动 鉴于您有名为的函数cost tile1 tile2 它告诉您从一个相邻图块移动到另一个图块的成本 您如何找到既可接受又一致的启发式函数 h y goal 给定此设置 寻找启发
  • 在大地图上实现A星(A*)路径算法,性能较低

    我正在使用这个 A 星 A Pathfinder java 在 Android 地图应用程序中计算和生成我的路线 https github com xSmallDeadGuyx SimpleAStar blob master Pathfin
  • 路径查找算法:A* 与跳跃点搜索

    我知道 A 比 Dijkstra 算法更好 因为它考虑了启发式值 但是从 A 和跳跃点搜索来看 哪种算法是在有障碍物的环境中找到最短路径的最有效算法 有何不同 跳跃点搜索是基于图表上的某些条件的改进的 A 因此 如果满足这些条件 主要是统一
  • 解决8字谜题的有效方法是什么?

    8 拼图是一块有 9 个位置的方板 由 8 个编号的图块和一个间隙填充 在任何时候 与间隙相邻的图块都可以移动到间隙中 从而创建新的间隙位置 换句话说 间隙可以与相邻 水平和垂直 的图块交换 游戏的目标是从任意配置的图块开始 然后移动它们以
  • 明星算法:距离启发式

    我正在使用 A 星算法 如此处所示 取自http code activestate com recipes 578919 python a pathfinding with binary heap http code activestate

随机推荐

  • 结构体(struct)

    什么是结构体 结构是程序员定义数据类型 xff0c 与类非常相似 它们有数据成员和函数成员 xff0c 虽然相似 xff0c 但是有许多区别 xff0c 区别如下 xff1a 类是引用类型二结构是值类型 结构是隐式密封的 xff0c 这意味
  • 【C语言】——结构体进阶:结构体的内存对齐(超详细)

    前言 xff1a 上一篇已经讲了结构体的基本用法 相信各位小伙伴以经学会怎么使用 但是还有一个问题没有弄明白 结构体到底多大 xff0c 占内存空间多不多 xff0c 以经系统到底怎么访问结构体内的数据的 接下来 xff0c 详细分析一下结
  • 【HTTP】摘要认证 Digest access authentication

    第三方接口对接 xff1a 摘要认证 Digest access authentication HTTP认证方式 xff1a BASIC 认证 xff08 基本认证 xff09 xff1b DIGEST 认证 xff08 摘要认证 xff0
  • 自己编译安装OpenCV (linux/windows)

    简单介绍一下OpenCV OpenCV 是 Open Source Computer Vision Library 的简称 xff0c 在计算机视觉领域中是一个非常重要的开源库 xff0c 该库使用的是BSD开源协议 xff0c 这个开源协
  • 基于TCP的项目学习历程(一)实现简单的socket请求。瞎扯的,不要评论。

    毕业至今不到两年 xff0c 但从大四刚开始就在外面开始从事开发工作了 但是一直从事的WEB项目的开发 xff0c 一直没啥长进 最近由于需要 xff0c 需要学习基于TCP的服务器开发 xff0c 由此决定 xff0c 写点东西 xff0
  • laravel框架如何生成Authorization值

    1 xff0c 创建密码授权客户端 在laravel当前目录执行 php artisan passport client password 生成如下值 Client ID 11 Client Secret fOxGavTYTJFP7Eqo0
  • eclipse mysql 数据库报错 com.mysql.jdbc.Driver

    eclipse 项目使用mysql数据库 报一下错误 Caused by java lang ClassNotFoundException com mysql jdbc Driver 解决方法 xff1a 1 xff1a 首先查看项目中是否
  • eclipse svn 报错 文件夹已经不存在

    最近做项目用eclipse 遇到个很奇怪的问题 xff0c 前几天svn还是可以用的 xff0c 突然一下子不能用了 xff0c 于是网上各种找解决方法啊 xff0c 终于问题解决了 xff0c 总结一下 查看svn报错信息 xff1a s
  • Java 提供接口供其它应用调用

    64 author 会员 接口类 相关参数协议 xff1a 00 请求失败 01 请求成功 02 返回空值 03 请求协议参数不完整 04 用户名或密码错误 05 FKEY验证失败 64 Controller 64 RequestMappi
  • H5 下载文件到本地

    H5 下载文件到本地 其实 xff0c 目前下载文件到本地有很多中方法 xff0c 不管是 JavaScript 或者 jQuery 也好 xff0c 都有各色各样的方法 xff0c 都可以做的到 xff0c 在这里我介绍下我发现的一个比较
  • Javaweb QQ第三方登录

    这是第三方登录的第二篇 xff0c 关于web接入微博第三方登录可以参考我之前的博文 xff0c 之前的博文比较详细的讲解了该如何进行第三方登录的申请和准备工作 http blog csdn net cwfjimogudan article
  • vmware 虚拟机启动失败, Intel VT-x 处于禁用状态

    错误提示 xff1a 已将该虚拟机配置为使用 64 位客户机操作系统 但是 xff0c 无法执行 64 位操作 此主机支持 Intel VT x xff0c 但 Intel VT x 处于禁用状态 如果已在 BIOS 固件设置中禁用 Int
  • java 35 个 Java 代码性能优化总结

    前言 代码优化 xff0c 一个很重要的课题 可能有些人觉得没用 xff0c 一些细小的地方有什么好修改的 xff0c 改与不改对于代码的运行效率有什么影响呢 xff1f 这个问题我是这么考虑的 xff0c 就像大海里面的鲸鱼一样 xff0
  • 基于51单片机超声波红外避障语音导盲仪设计(全套资料)

    基于51单片机的超声波红外避障语音导盲仪设计 本系统采用STC89C52单片机 43 4位高亮白色LED灯 43 红外避障传感器电路 43 超声波电路 43 光敏电阻模块 43 语音报警电路 43 震动电路 43 液晶1602电路 43 电
  • linux 解压zip压缩包命令

    unzip 文件名 zip d 解压位置 例如 xff1a unzip 微信 zip d demowx
  • linux 文件授权命令

    文件授权 chmod 43 x sh
  • linux tomcat常用命令

    startup sh 启动tomcat shutdown sh 关闭tomcat ps ef grep tomcat 查看Tomcat运行 kill 9 4723 杀进程 tail f catalina out 查看tomcat运行日志 c
  • linux redis常用命令

    flushall 清空redis缓存 redis cli 进入redis xff08 需要进入redis的安装目录下 xff09 get key 查找key del key 删除key
  • java DateUtils时间工具栏

    package com eeye common utils import org apache commons lang3 time DateFormatUtils import java text ParseException impor
  • unity3d:Astar寻路,A星,A*,二叉堆优化Open表

    原理视频 油管 xff1a https youtu be i0x5fj4PqP4 别人的B站翻译 xff1a https www bilibili com video BV1v44y1h7Dt spm id from 61 333 999