美文网首页
A*寻路算法

A*寻路算法

作者: BugUnknown | 来源:发表于2018-08-24 20:47 被阅读15次
    寻路效果.gif

    代码实现

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    /// <summary>
    /// 格子类型
    /// </summary>
    public enum ItemType
    {
        Normal,
        Obsticle,
        Start,
        End
    }
    
    public class AStar : MonoBehaviour
    {
        /// <summary>
        /// Item预设体
        /// </summary>
        public GameObject itemPrefab;
        //起点终点坐标
        public int startPointX = 1;
        public int startPointY = 2;
        public int endPointX = 10;
        public int endPointY = 12;
        //自定义偏移量
        public float offset = 0.5f;
        //障碍物出现的概率
        public int obsticleScale = 60;
        //地图格子的长宽
        private int mapX;
        private int mapY;
        //地图偏移量
        private float mapOffsetX;
        private float mapOffsetY;
        //格子数组
        private Item[,] items;
        /// <summary>
        /// 开启列表(将所有计算过FGH值的格子存储)
        /// </summary>
        private List<Item> openList;
        /// <summary>
        /// 关闭列表(将被作为中心计算过的格子)
        /// </summary>
        private List<Item> closeList;
        /// <summary>
        /// 结果路径
        /// </summary>
        private Stack<Item> path;
    
        void Awake()
        {
            openList = new List<Item>();
            closeList = new List<Item>();
            path = new Stack<Item>();
        }
    
        void Start()
        {
            MapReady();
            AStarPathFinding();
        }
    
        /// <summary>
        /// 地图准备
        /// </summary>
        void MapReady()
        {
            //计算地图长宽
            mapX = (int)(transform.localScale.x * 20);
            mapY = (int)(transform.localScale.z * 20);
            //实例数组
            items = new Item[mapX, mapY];
            //计算地图偏移量
            mapOffsetX = -transform.localScale.x * 10 / 2;
            mapOffsetY = -transform.localScale.z * 10 / 2;
            //生成格子
            for (int i = 0; i < mapX; i++)
            {
                for (int j = 0; j < mapY; j++)
                {
                    //获取当前格子
                    GameObject crtItem = Instantiate(itemPrefab,
                        new Vector3(i / 2f, 0, j / 2f) +
                        new Vector3(mapOffsetX + offset, 0,
                            mapOffsetY + offset),
                        Quaternion.identity);
                    //填充数组
                    items[i, j] = crtItem.GetComponent<Item>();
                    //设置坐标
                    items[i, j].SetItemXY(i, j);
                    //随机
                    int r = Random.Range(1, 101);
                    if (r <= obsticleScale)
                    {
                        //设置障碍物
                        items[i, j].SetItemType(ItemType.Obsticle);
                    }
                }
            }
            //设置起点终点
            items[startPointX, startPointY].SetItemType(ItemType.Start);
            items[endPointX, endPointY].SetItemType(ItemType.End);
        }
    
        /// <summary>
        /// A*寻路
        /// </summary>
        void AStarPathFinding()
        {
            //起点格子作为当前格子
            Item currentItem = null;
            //添加起点格子到开启列表
            openList.Add(items[startPointX, startPointY]);
            //循环遍历
            while (openList.Count > 0)
            {
                //获取F值最小的格子作为当前格子
                currentItem = openList[0];
                //如果发现了终点
                if (currentItem.GetItemType()
                   == ItemType.End)
                {
                    //TODO:整理结果路径
                    GeneratePath(currentItem);
                    return;
                }
                //发现周围的格子
                for (int i = -1; i <= 1; i++)
                {
                    for (int j = -1; j <= 1; j++)
                    {
                        //越过当前格子
                        if (i == 0 && j == 0)
                            continue;
                        //被发现的格子坐标
                        int p = currentItem.GetItemX() + i;
                        int q = currentItem.GetItemY() + j;
                        if (p < 0 || q < 0 || p >= mapX
                           || q >= mapY ||
                           items[p, q].GetItemType() == ItemType.Obsticle ||
                            closeList.Contains(items[p, q]))
                        {
                            continue;
                        }
                        //计算FGH
                        int g = currentItem.g + (int)(Mathf.Sqrt(i * i + j * j) * 10);
                        //如果该格子的g未被计算,或值太大,覆盖它
                        if (items[p, q].g == 0 || items[p, q].g > g)
                        {
                            items[p, q].g = g;
                            //设置发现者
                            items[p, q].parent = currentItem;
                        }
                        //曼哈顿计算h值
                        items[p, q].h = (Mathf.Abs(p - endPointX)
                            + Mathf.Abs(q - endPointY)) * 10;
                        //计算F
                        items[p, q].f = items[p, q].g + items[p, q].h;
                        //添加到开启列表
                        openList.Add(items[p, q]);
                    }
                }
                //For循环结束
                //移除当前格子从开启列表
                openList.Remove(currentItem);
                //放置到关闭列表
                closeList.Add(currentItem);
                //判断
                if (openList.Count == 0)
                    Debug.Log("无法到达目标点!");
                //排序
                openList.Sort();
            }
        }
    
        /// <summary>
        /// 生成路径
        /// </summary>
        void GeneratePath(Item item)
        {
            if (item.parent != null)
            {
                //压栈
                path.Push(item.parent);
                //递归寻址
                GeneratePath(item.parent);
            }
            else
            {
                //输出结果
                StartCoroutine(ShowPath());
            }
        }
    
        /// <summary>
        /// 展示结果
        /// </summary>
        /// <param name="item">Item.</param>
        IEnumerator ShowPath()
        {
            while (path.Count > 0)
            {
                //出栈
                Item item = path.Pop();
                if (item.GetItemType() != ItemType.Start)
                {
                    //标记
                    item.SetColor(Color.black);
                }
                yield return new WaitForSeconds(0.2f);
            }
        }
    
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                UnityEngine.SceneManagement.SceneManager.LoadScene(0);
            }
        }
    }
    
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class Item : MonoBehaviour, System.IComparable
    {
    
        //格子类型
        private ItemType itemType;
        //格子坐标
        private int x;
        private int y;
        //寻路估量代价值
        public int f;
        public int g;
        public int h;
        //当前格子的发现者
        public Item parent;
    
        private MeshRenderer meshRenderer;
    
        void Awake()
        {
            meshRenderer = GetComponent<MeshRenderer>();
        }
        /// <summary>
        /// 设置格子类型
        /// </summary>
        /// <param name="t">T.</param>
        public void SetItemType(ItemType t)
        {
            //设置
            itemType = t;
            switch (t)
            {
                case ItemType.Start:
                    meshRenderer.material.color = Color.red;
                    break;
                case ItemType.End:
                    meshRenderer.material.color = Color.green;
                    break;
                case ItemType.Obsticle:
                    meshRenderer.material.color = Color.blue;
                    break;
                default:
                    meshRenderer.material.color = Color.white;
                    break;
            }
        }
    
        /// <summary>
        /// 获取格子类型
        /// </summary>
        /// <returns>The item type.</returns>
        public ItemType GetItemType()
        {
            return itemType;
        }
    
        public int GetItemX()
        {
            return x;
        }
    
        public int GetItemY()
        {
            return y;
        }
    
        /// <summary>
        /// 设置坐标
        /// </summary>
        /// <param name="x">The x coordinate.</param>
        /// <param name="y">The y coordinate.</param>
        public void SetItemXY(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        /// <summary>
        /// 上色
        /// </summary>
        /// <param name="col">Col.</param>
        public void SetColor(Color col)
        {
            meshRenderer.material.color = col;
        }
    
        /// <summary>
        /// 排序规则
        /// </summary>
        /// <returns>The to.</returns>
        /// <param name="obj">Object.</param>
        public int CompareTo(object obj)
        {
            //新的Item
            Item newItem = obj as Item;
            if (newItem.f > this.f)
            {
                return -1;
            }
            else if (newItem.f < this.f)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:A*寻路算法

          本文链接:https://www.haomeiwen.com/subject/duzviftx.html