Unity A*寻路 路劲规划

Unity A*寻路

namespace AStar
{
    //格子类型
    public enum AStarType
    {
        WALK,
        STOP
    }
    public class AStarNode
    {
        public AStarNode() { }
        public AStarNode(int x, int y, AStarType type)
        {
            this.x = x;
            this.y = y;
            this.type = type;
        }

        //父格子
        public AStarNode father;
        //格子位置
        public int x;
        public int y;
        //public Vector2 pos;
        //地图格子类型
        public AStarType type;
        //寻路消耗 欧拉距离+曼哈顿距离
        public float f;
        //距离起点距离 欧拉距离
        public float g;
        //距离终点距离 曼哈顿距离
        public float h;
        //重置节点信息
        public void ResetNode()
        {
            this.father = null;
            this.f = 0;
            this.g = 0;
            this.h = 0;
        }
    }
}
using System.Collections.Generic;
using UnityEngine;

namespace AStar
{
    public class AStarMgr
    {
        private static AStarMgr instance = new AStarMgr();
        public static AStarMgr Instance { get => instance; private set => instance = value; }

        private int mapW;

        private int mapH;
        //地图信息
        public AStarNode[,] nodes;
        //开启列表
        private List<AStarNode> openList;
        //关闭列表
        private List<AStarNode> closeList;

        private List<AStarNode> path = new List<AStarNode>();

        //加载地图信息
        public void InitMaps(int w, int h)
        {
            mapW = w;
            mapH = h;
            openList = new List<AStarNode>();
            closeList = new List<AStarNode>();
            nodes = new AStarNode[w, h];
            for (var i = 0; i < w; i++)
            {
                for (var j = 0; j < h; j++)
                {
                    var node = new AStarNode(i, j, Random.Range(0, 100) < 20 ? AStarType.STOP : AStarType.WALK);
                    nodes[i, j] = node;
                }
            }
        }
        //寻路
        public List<AStarNode> FindPath(Vector2 startPos, Vector2 endPos)
        {
            var startNode = GetNode(startPos);
            var endNode = GetNode(endPos);
            if (!CheckNode(startNode.x, startNode.y) || !CheckNode(endNode.x, endNode.y) || !CheckType(startNode) || !CheckType(endNode)) return null;
            startNode.ResetNode();
            openList.Clear();
            closeList.Clear();
            AddCloseList(startNode);
            while (true)
            {
                FineNearNodeToOpenList((int)startNode.x - 1, (int)startNode.y - 1, 1.4f, startNode, endNode);
                FineNearNodeToOpenList((int)startNode.x, (int)startNode.y - 1, 1f, startNode, endNode);
                FineNearNodeToOpenList((int)startNode.x + 1, (int)startNode.y - 1, 1.4f, startNode, endNode);
                FineNearNodeToOpenList((int)startNode.x - 1, (int)startNode.y, 1f, startNode, endNode);
                FineNearNodeToOpenList((int)startNode.x + 1, (int)startNode.y, 1f, startNode, endNode);
                FineNearNodeToOpenList((int)startNode.x - 1, (int)startNode.y + 1, 1.4f, startNode, endNode);
                FineNearNodeToOpenList((int)startNode.x, (int)startNode.y + 1, 1f, startNode, endNode);
                FineNearNodeToOpenList((int)startNode.x + 1, (int)startNode.y + 1, 1.4f, startNode, endNode);

                //死路
                if (openList.Count == 0) return null;

                openList.Sort(SortOpenList);
                AddCloseList(openList[0]);
                startNode = openList[0];
                openList.RemoveAt(0);
                if (startNode == endNode)
                {
                    path.Clear();
                    path.Add(endNode);
                    while (endNode.father != null)
                    {
                        path.Add(endNode.father);
                        endNode = endNode.father;
                    }
                    path.Reverse();
                    return path;
                }
            }
        }
        //从地图信息中获取对应的AStarNode
        private AStarNode GetNode(Vector2 pos)
        {
            return nodes[(int)pos.x, (int)pos.y];
        }
        //判断合法
        private bool CheckNode(int x, int y)
        {
            //在范围内
            if (x < 0 || x >= mapW || y < 0 || y >= mapH) return false;
            return true;
        }
        //判断类型
        private bool CheckType(AStarNode node)
        {
            if (node.type == AStarType.WALK) return true;
            return false;
        }
        //添加到开启列表
        private void AddOpenList(AStarNode node)
        {

            if (!openList.Contains(node))
                openList.Add(node);
        }
        //添加到关闭列表
        private void AddCloseList(AStarNode node)
        {

            if (!closeList.Contains(node))
                closeList.Add(node);
        }

        //获取周围的点添加到开启列表
        private void FineNearNodeToOpenList(int x, int y, float g, AStarNode father, AStarNode end)
        {
            if (!CheckNode(x, y)) return;
            var tempNode = nodes[x, y];
            if (tempNode == null || !CheckType(tempNode) || openList.Contains(tempNode) || closeList.Contains(tempNode))
                return;
            //计算寻路消耗
            tempNode.father = father;
            tempNode.g = father.g + g;
            tempNode.h = Mathf.Abs(end.x - tempNode.x) + Mathf.Abs(end.y - tempNode.y);
            tempNode.f = tempNode.g + tempNode.h;
            openList.Add(tempNode);

        }

        private int SortOpenList(AStarNode a, AStarNode b)
        {
            if (a.f > b.f) return 1;
            else return -1;
        }
    }
}
using System.Collections.Generic;
using UnityEngine;

namespace AStar
{
    public class AStarTest : MonoBehaviour
    {
        public int BeginX = 3;
        public int BeginY = -5;
        public int MapW = 5;
        public int MapH = 5;
        public int OffetX = 2;
        public int OffetY = 2;
        private Vector2 beginPos = Vector2.right * -1;
        private Dictionary<string, GameObject> cubes = new Dictionary<string, GameObject>();
        private List<AStarNode> path;
        private void Start()
        {
            path = new List<AStarNode>();
            AStarMgr.Instance.InitMaps(MapW, MapH);
            for (int i = 0; i < MapW; i++)
            {
                for (int j = 0; j < MapH; j++)
                {
                    var obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
                    obj.transform.position = new Vector3(BeginX + i * OffetX, BeginY + j * OffetY, 0);
                    obj.name = i + "_" + j;
                    cubes.Add(obj.name, obj);
                    var node = AStarMgr.Instance.nodes[i, j];
                    if (node.type == AStarType.STOP)
                    {
                        obj.GetComponent<MeshRenderer>().material.color = Color.red;
                    }
                }
            }
        }

        private void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                RaycastHit hitInfo;
                var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                if (Physics.Raycast(ray, out hitInfo, 1000))
                {
                    if (beginPos == Vector2.right * -1)
                    {
                        if (path != null)
                        {
                            foreach (var item in path)
                            {
                                cubes[item.x + "_" + item.y].GetComponent<MeshRenderer>().material.color = Color.white;
                            }
                        }
                        string[] strs = hitInfo.collider.gameObject.name.Split('_');
                        beginPos = new Vector2(int.Parse(strs[0]), int.Parse(strs[1]));
                        hitInfo.collider.gameObject.GetComponent<MeshRenderer>().material.color = Color.yellow;
                    }
                    else
                    {
                        string[] strs = hitInfo.collider.gameObject.name.Split('_');
                        var endPos = new Vector2(int.Parse(strs[0]), int.Parse(strs[1]));
                        hitInfo.collider.gameObject.GetComponent<MeshRenderer>().material.color = Color.green;
                        //寻路
                        path = AStarMgr.Instance.FindPath(beginPos, endPos);
                        if (path != null)
                        {
                            foreach (var item in path)
                            {
                                cubes[item.x + "_" + item.y].GetComponent<MeshRenderer>().material.color = Color.green;
                            }
                        }
                        beginPos = Vector2.right * -1;
                    }
                }
            }
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Winjet_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值