简单AStar寻路2D示例

A*寻路

在这里插入图片描述

牢记A*寻路的核心

F(n) = G(n) + H(n)
G(n): 从起始位置到n位置所需的实际消耗
H(n): 从n位置到目标位置的预计消耗
所以F(n)就是从起始位置经过n位置到目标位置的路径总消耗
A*寻路的过程就是不断找最小F(n)的过程

A*寻路流程

1.加入“开启列表”
先将起点作为当前检查点加入“开启列表”,“开启列表”是一个等待检查方格的列表,起点格子是最开始的检查点
2.检查周围
将当前检查点周围可到达的点加入“开启列表”,并设置它们的"父节点"为当前的检查点,并且计算出这些点的G(n)、H(n)、F(n)值
如果周围的点已经有在“开启列表” 中,则我们需要对比新旧路径的G值,如果新路径的G值更小,则使用新路径,需要更新“父节点”
如果是障碍物,则忽略
3.移入“关闭列表”
将这个检查点从“开启列表”移到“关闭列表”,"关闭列表"中存放的都是不需要再次检查的格子点
4.继续找直到找不到或者找到为止
再从“开启列表”中找出F值最小的格子,然后从上述的第1步开始重复继续,直到找到的F值最小的格子为终点或者“开启列表”中没有格子了,即为结束

几点注意点

  1. H(n)预计消耗的计算的准确度非常重要
    由于G(n)是已经走过的路,所需的消耗是明确的,只有H(n)是预计的,预计的越准,我们就能越快的找到目标位置,减少计算量,也能更贴近最短路径
  2. A*寻路的结果并不一定是最短
    由于H(n)是预计的消耗,这个预计的消耗可能会出现与实际情况相差较大的情况,这个时候寻路结果可能不是最短的

纸上得来终觉浅,绝知此事要躬行

简单做了个示例演示A*寻路的过程,以辅助理解
地图随机生成指定数量的障碍物,随机指定起始位置和终点位置
Game视图 Esc重置地图 Space 执行一步寻路步骤
白色:未检查过的格子
黑色:障碍物
黄色:在“开启列表”中的格子
灰色:在“关闭列表”中的格子
红色:目标格子
绿色:当前正在检查的格子
绿色链:最终的寻路结果
格子左上角:G值
格子右上角:H值
格子左下角:F值
格子右下角:坐标
箭头:指向寻路过程中的父格子

这里随机两次寻路过程来看下:
在这里插入图片描述
在这里插入图片描述
看下最终的寻路图
在这里插入图片描述

代码

完整工程:
Unity版本:2020.3.10

AStarGrid

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AStarGrid
{
   
   
    public int X {
   
    get; set; }  //坐标X
    public int Y {
   
    get; set; }  //坐标Y
    public float F {
   
    get {
   
    return G + H; } }  
    public float G {
   
    get; set; }
    public float H {
   
    get; set; }
    public bool IsObstacle {
   
    get; set; }
    public AStarGrid ParentGrid {
   
    get; set; }

    public AStarGrid(int x, int y)
    {
   
   
        this.X = x;
        this.Y = y;
    }

    public void Reset()
    {
   
   
        G = 0;
        H = 0;
        IsObstacle = false;
        ParentGrid = null;
    }
}

AStarMap

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AStarMap
{
   
   
    AStarGrid[,] map;
    int mapWidth;
    int mapHeight;

    //开启列表
    Dictionary<int, AStarGrid> openList = new Dictionary<int, AStarGrid>();
    //关闭列表
    Dictionary<int, AStarGrid> closeList = new Dictionary<int, AStarGrid>();

    public AStarMap(int mapWidth, int mapHeight)
    {
   
   
        this.mapWidth = mapWidth;
        this.mapHeight = mapHeight;
        map = new AStarGrid[mapWidth, mapHeight];
        for (int w = 0; w < mapWidth; w++)
        {
   
   
            for (int h = 0; h < mapHeight; h++)
            {
   
   
                map[w, h] = new AStarGrid(w, h);
            }
        }
    }

    public void SetObstacle(int x, int y, bool isObstacle)
    {
   
   
        map[x, y].IsObstacle = isObstacle;
    }

    public AStarGrid GetGrid(int x, int y)
    {
   
   
        return map[x, y];
    }

    /// <summary>
    /// 直接寻路,返回寻路结果
    /// </summary>
    /// <param name="startX"></param>
    /// <param name="startY"></param>
    /// <param name="targetX"></param>
    /// <param name="targetY"></param>
    /// <returns></returns>
    public List<AStarGrid> FindPath(int startX, int startY, int targetX, int targetY)
    {
   
   
        openList.Clear();
        closeList.Clear();

        var startGrid = map[startX, startY];
        var targetGrid = map[targetX, targetY];
        var grid = startGrid;
        AddToOpenList(grid, null, targetGrid);  //先将起点加入“开启列表”,“开启列表”是一个等待检查方格的列表,起点格子是最开始的检查点
        while (grid != null)  //null时意味着找不到路径
        {
   
   
            if (<
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值