理解A*寻路算法具体过程

 A*寻路

这里写图片描述
创建网格节点类

using UnityEngine;
using System.Collections;

public class Node {

    public float radium; // 半径
    public int x, y; // 下标
    public float gCost = 0, hCost = 0, fCost = 0;   // 估价值 
    public Node parent;  // 父节点
    public bool canWalk;// 能否行走,是否有障碍物
    public Vector3 worldPos;// 世界坐标

   public Node(int x, int y, bool canWalk, Vector3 worldPos)
    {// 初始化变量
       this.x = x;
       this.y = y;
       this.canWalk = canWalk;
       this.worldPos = worldPos;
   }



}

创建网格

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Grid : MonoBehaviour
{
    public float gridSize;// 网格大小
    public float nodeRadius;// 每一个小格子的半径
    float nodeDia;// 小格子的直径
    int countX, countY;// 水平格子数量和垂直格子数量
    Node[,] grid;// 网格
    public LayerMask obsLayer;// 障碍物所在层
    public List<Node> paths;// 最终可行路径
    public void Start()
    {// 初始化变量
        nodeDia = nodeRadius * 2;
        countX = Mathf.CeilToInt(gridSize / nodeDia);
        countY = countX;
        grid = new Node[countX, countY];
        initGrid();
    }

    /// <summary>
    /// 初始化网格矩阵
    /// </summary>
    private void initGrid()
    {
        Vector3 startPos = transform.position - new Vector3(gridSize / 2, 0, gridSize / 2);
        for (int i = 0; i < countX; i++)
        {
            for (int j = 0; j < countY; j++)
            {
                // 获取小方格的世界坐标点
                Vector3 pos = startPos + new Vector3(i * nodeDia + nodeRadius, 0, j * nodeDia + nodeRadius);
                // 判断小方格周围是否有障碍物
                bool canWalk = !Physics.CheckSphere(pos, nodeRadius, obsLayer);
                Node node = new Node(i, j, canWalk, pos);
                grid[i, j] = node;
            }
        }
    }

    public void OnDrawGizmos()
    {
        //Gizmos.DrawCube(transform.position, new Vector3(gridSize, 1, gridSize));
        // 绘制网格矩阵
        if (grid != null)
        {
            for (int i = 0; i < countX; i++)
            {
                for (int j = 0; j < countY; j++)
                {
                    if (grid[i, j].canWalk)
                    {// 如果可以行走,绘制为绿色或白色
                        if(i>countX/2 && j>countY/2 || i<countX/2 && j<countY/2){
                            Gizmos.color = Color.green;
                        }
                        else Gizmos.color = Color.white;

                    }
                    else Gizmos.color = Color.red;// 如果不可以行走,绘制为红色
                    Gizmos.DrawCube(grid[i,j].worldPos, new Vector3(nodeDia - 0.2f, 0.2f, nodeDia - 0.2f));
                }
            }
        }
        // 绘制最终路径网格
        if(paths!=null && paths.Count>0){
            Gizmos.color = Color.cyan;
            foreach (var item in paths)
            {
                Gizmos.DrawCube(item.worldPos, new Vector3(nodeDia - 0.2f, 0.2f, nodeDia - 0.2f));

            }

        }

    }

    /// <summary>
    /// 通过世界坐标点,获取对应网格的坐标值
    /// </summary>
    /// <param name="pos"></param>
    /// <returns></returns>
    public Node GetNodeByPos(Vector3 pos) {
        Vector3 reaPos = pos - transform.position;//相对坐标位置
        //Debug.Log("reaPosl" + reaPos);
        float percentX = (reaPos.x + gridSize / 2) / gridSize;
        float percentY = (reaPos.z + gridSize / 2) / gridSize;
        int X = Mathf.CeilToInt(countX * percentX)-1;
        int Y = Mathf.CeilToInt(countY * percentY)-1;
        if (grid != null)
        {
            return grid[X, Y];
        }
        else return null;
    }

    /// <summary>
    /// 通过一个格子,根据九宫格,获取周围8个相邻格子
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    public List<Node> GetNeighborNodes(Node node)
    {
        List<Node> nodeList = new List<Node>();
        int x = node.x;
        int y = node.y;
        for (int i = -1; i <=1; i++)
        {
            for (int j = -1; j <= 1; j++)
            {
               if(x+i>=0 && y+j>=0&& x+i<countX && y+j<countY){
                   nodeList.Add(grid[x + i, y + j]);
               }
            }
        }

        return nodeList;
    }


}

寻路

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Paths : MonoBehaviour
{
    float cost1;// 相邻两个格子的水平估价
    float cost2;//相邻两个格子的对角线估价
    Grid grid;
    bool isMove = false;
    int index = 0;
    Vector3 des;
    public Transform moveTarget;//移动对象
    public static Paths Instance;//创建单例

    public void Awake()
    {
        Instance = this;
    }

    void Start()
    {

        grid = GetComponent<Grid>();
        cost1 = grid.nodeRadius * 2;
        cost2 = Mathf.Sqrt(grid.nodeRadius * 2 * grid.nodeRadius * 2 * 2);//对角线
        //setDis(enemy.position);
    }
    // Update is called once per frame
    void Update()
    {

    }

    //设置寻路目标点
    public  void setDis(Vector3 destination)
    {
        findPath(moveTarget.position, destination);

    }

    //停止寻路
    public void StopDis() {
        grid.paths = null;
    }

    /// <summary>
    /// 获取从起始点到终点的最近路程
    /// </summary>
    /// <param name="beginPos">起始点</param>
    /// <param name="destination">终点</param>
    private  void findPath(Vector3 beginPos, Vector3 destination)
    {
        List<Node> openList = new List<Node>();//创建开启列表
        List<Node> closeList = new List<Node>();//创建关闭列表

        Node beginNode = grid.GetNodeByPos(beginPos);
        Node EndNode = grid.GetNodeByPos(destination);
        Node currentNode = beginNode;//将当前节点保存到开启列表
        openList.Add(currentNode);
        while (currentNode != EndNode)
        {
            if (openList.Count <= 0) { break; }

            currentNode = openList[0];

            //从开启列表寻找估价最小的节点
            for (int i = 0; i < openList.Count; i++)
            {

                if (openList[i].fCost < currentNode.fCost || (openList[i].fCost == currentNode.fCost && openList[i].hCost < currentNode.hCost))
                {
                    currentNode = openList[i];
                }
            }

            closeList.Add(currentNode);//将当前节点添加到关闭列表
            openList.Remove(currentNode);//将当前节点从开启列表移出
            if (currentNode == EndNode)
            {//如果寻路到达终点,生成最终路径
                grid.paths = GeneratePath(beginNode, EndNode);
                return;
            }
            //获取当前节点周围8个点,如果它们不在关闭集合并且可以行走,计算它们的估价,并添加到开启集合

            List<Node> neiborList = grid.GetNeighborNodes(currentNode);
            foreach (Node item in neiborList)
            {
                float gCost = GetNodesCost(item, currentNode) + currentNode.gCost;
                float hCost = GetNodesCost(item, EndNode);


                if (item == null || closeList.Contains(item) || !item.canWalk)
                {
                    continue;
                }
                //如果已经保存在开启集合,计算新的g估价大于原先估价,更新其估计和父节点
                if (openList.Contains(item))
                {
                    if (gCost < item.gCost)
                    {
                        item.gCost = gCost;
                        item.parent = currentNode;
                    }
                }
                else
                {
                    item.gCost = gCost;
                    item.hCost = hCost;
                    item.parent = currentNode;
                    openList.Add(item);

                }
            }

        }
    }

    /// <summary>
    /// 生成最终路径
    /// </summary>
    /// <param name="beginNode">起始节点</param>
    /// <param name="EndNode">终止节点</param>
    /// <returns></returns>
    private List<Node> GeneratePath(Node beginNode, Node EndNode)
    {//通过寻找父节点的方式,生成从终点到起始点的路径,然后将集合取反,生成最终路径
        List<Node> path = new List<Node>();
        Node temp = EndNode;
        while (temp != beginNode)
        {
            path.Add(temp);
            temp = temp.parent;
        }
        path.Reverse();//取反
        return path;
    }

    /// <summary>
    /// 获取两个节点之间的估价值
    /// </summary>
    /// <param name="item"></param>
    /// <param name="currentNode"></param>
    /// <returns></returns>
    private float GetNodesCost(Node item, Node currentNode)
    {
        //计算节点坐标水平和垂直的差值
        int offsetX = Mathf.Abs(item.x - currentNode.x);
        int offsetY = Mathf.Abs(item.y - currentNode.y);
        float dis;
        //让小的差值乘于对角线估价,大的差值与小的差值的差乘于水平估价
        if (offsetX >= offsetY)
        {
            dis = offsetY * cost2 + (offsetX - offsetY) * cost1;
        }
        else
        {
            dis = offsetX * cost2 + (offsetY - offsetX) * cost1;
        }
        return dis;
    }




}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天涯过客TYGK

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值