【A*算法】Unity写的一个A*算法的实例,帮助你理解A*寻路思想

9 篇文章 0 订阅

A*算法核心类:

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

namespace YSFrame
{
    public class YsPath
    {
        private  static Transform cubesGroups;
        private static YsPath _instance;
        //存储路径方格子
        public List<Object> mPathPosList = new List<Object>();
        public static void  InitYsPath()
        {
            cubesGroups = GameObject.FindGameObjectWithTag("Groups").transform;
        }
        public static YsPath GetInsatnce
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new YsPath();
                }

                return _instance;
            }
        }
        public void ClearGrid()
        {
            List<Object> _cubeList = new List<Object>();
            for (int i = 0; i < cubesGroups.childCount; i++)
            {
                if (cubesGroups.GetChild(i).gameObject.activeInHierarchy)
                {
                    _cubeList.Add(cubesGroups.GetChild(i).GetComponent<Object>());
                }
            }
            for (int i = 0; i < _cubeList.Count; i++)
            {
                if (_cubeList[i].layer!=EA.LayerType.Obstancle)
                {
                    //重新设置父节点
                    _cubeList[i].mParentPoint = null;
                }
            }

        }
        //寻路
        public List<Object> FindPath(Object mStartPoint, Object mEndPoint)
        {
            if (mEndPoint.layer == EA.LayerType.Obstancle || mStartPoint.baseTransfrom.vector3 == mEndPoint.baseTransfrom.vector3||mEndPoint.type!=EA.ObjectType.Cube)
            {
                return null;
            }

            //开启列表
            List<Object> openPointList = new List<Object>();
            //关闭列表
            List<Object> closePointList = new List<Object>();

            openPointList.Add(mStartPoint);

            while (openPointList.Count > 0)
            {
                //寻找开启列表中最小预算值的表格
                Object minFPoint = FindPointWithMinF(openPointList);
                //将当前表格从开启列表移除 在关闭列表添加
                openPointList.Remove(minFPoint);
                closePointList.Add(minFPoint);
                //找到当前点周围的全部点
                List<Object> surroundPoints = FindSurroundPoint(minFPoint);
                //排除障碍物的点
                for (int i = 0; i < surroundPoints.Count; i++)
                {
                    if (surroundPoints[i].layer == EA.LayerType.Obstancle)
                    {
                        surroundPoints.Remove(surroundPoints[i]);
                    }
                }
                //在周围的点中,将关闭列表里的点移除掉
                SurroundPointsFilter(surroundPoints, closePointList);
                //寻路逻辑
                foreach (var surroundPoint in surroundPoints)
                {
                    if (openPointList.Contains(surroundPoint))
                    {
                        //计算下新路径下的G值(H值不变的,比较G相当于比较F值)
                        float newPathG = CalcG(surroundPoint, minFPoint);
                        if (newPathG < surroundPoint.mG)
                        {
                            surroundPoint.mG = newPathG;
                            surroundPoint.mF = surroundPoint.mG + surroundPoint.mH;
                            surroundPoint.mParentPoint = minFPoint;
                        }
                    }
                    else
                    {
                        //将点之间的
                        surroundPoint.mParentPoint = minFPoint;
                        CalcF(surroundPoint, mEndPoint);
                        openPointList.Add(surroundPoint);
                    }
                }

                //如果开始列表中包含了终点,说明找到路径
                if (openPointList.IndexOf(mEndPoint) > -1)
                {
                    break;
                }
            }

            return ShowPath(mStartPoint, mEndPoint);
        }
        private List<Object> ShowPath(Object start, Object end)
        {
            mPathPosList.Clear();

            Object temp = end;
            while (true)
            {
                mPathPosList.Add(temp);

                Color c = Color.white;
                if (temp == start)
                {
                    c = Color.green;
                }
                else if (temp == end)
                {
                    c = Color.red;
                }
                if (temp.mParentPoint == null)
                    break;
                temp = temp.mParentPoint;
            }
            return mPathPosList;
        }
        //寻找预计值最小的格子
        private Object FindPointWithMinF(List<Object> openPointList)
        {
            float f = float.MaxValue;
            Object temp = null;
            foreach (Object p in openPointList)
            {
                if (p.mF < f)
                {
                    temp = p;
                    f = p.mF;
                }
            }
            return temp;
        }
        //寻找周围的全部点
        private List<Object> FindSurroundPoint(Object point)
        {
            List<Object> list = new List<Object>();

            判断周围的4个点是否在网格内/
            Object up = null, down = null, left = null, right = null;
            up = GetObjectByPoints(point.baseTransfrom.vector3 + new Vector3(0, 0, 1));
            down = GetObjectByPoints(point.baseTransfrom.vector3 + new Vector3(0, 0, -1));
            left = GetObjectByPoints(point.baseTransfrom.vector3 + new Vector3(-1, 0, 0));
            right = GetObjectByPoints(point.baseTransfrom.vector3 + new Vector3(1, 0, 0));
            /将可以经过的表格添加到开启列表中/
            if (down != null && down.layer != EA.LayerType.Obstancle)
            {
                list.Add(down);
            }
            if (up != null && up.layer != EA.LayerType.Obstancle)
            {
                list.Add(up);
            }
            if (left != null && left.layer != EA.LayerType.Obstancle)
            {
                list.Add(left);
            }
            if (right != null && right.layer != EA.LayerType.Obstancle)
            {
                list.Add(right);
            }
            return list;
        }
        //根据点找对应的Object
        public static Object GetObjectByPoints(Vector3 v3)
        {
            List<Object> cubeList=new List<Object>();
            for (int i = 0; i < cubesGroups.childCount; i++)
            {
                if (cubesGroups.GetChild(i).gameObject.activeInHierarchy)
                {
                    cubeList.Add(cubesGroups.GetChild(i).GetComponent<Object>());
                }
            }

            for (int i = 0; i < cubeList.Count; i++)
            {
                if (cubeList[i].baseTransfrom.vector3.x==v3.x&& cubeList[i].baseTransfrom.vector3.z==v3.z)
                {
                    return cubeList[i];
                }
            }
            return null;
        }
        //将关闭带你从周围点列表中关闭
        private void SurroundPointsFilter(List<Object> surroundPoints, List<Object> closePoints)
        {
            foreach (var closePoint in closePoints)
            {
                if (surroundPoints.Contains(closePoint))
                {
                    Debug.Log("将关闭列表的点移除");
                    surroundPoints.Remove(closePoint);
                }
            }
        }
        //计算最小预算值点G值
        private float CalcG(Object surround, Object minFPoint)
        {
            return Vector3.Distance(surround.baseTransfrom.vector3, minFPoint.baseTransfrom.vector3) + minFPoint.mG;
        }

        //计算该点到终点的F值
        private void CalcF(Object now, Object end)
        {
            //F = G + H
            float h = Mathf.Abs(end.baseTransfrom.vector3.x - now.baseTransfrom.vector3.x) + Mathf.Abs(end.baseTransfrom.vector3.z - now.baseTransfrom.vector3.z);
            float g = 0;
            if (now.mParentPoint == null)
            {
                g = 0;
            }
            else
            {
                g = Vector2.Distance(new Vector2(now.baseTransfrom.vector3.x, now.baseTransfrom.vector3.z), new Vector2(now.mParentPoint.baseTransfrom.vector3.x, now.mParentPoint.baseTransfrom.vector3.z)) + now.mParentPoint.mG;
            }
            float f = g + h;
            now.mF = f;
            now.mG = g;
            now.mH = h;
        }
    }
}



Object(自定义基类)

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

namespace YSFrame
{
    [Serializable]
    public class Object : MonoBehaviour
    { 

        public static Dictionary<int, GameObject> ODict = new Dictionary<int, GameObject>();
        [Header("ID")]
        public int ID;
        [Header("物品类型")]
        public EA.ObjectType type;
        [Header("寻路层级性质")]
        public EA.LayerType layer;
        [Header("依附父级方块ID")]
        public int parentCubeID;//0代表没有
        [Header("信息")]
        public string message;
        [Header("Transfrom")]
        public BaseTransfrom baseTransfrom;

        //父“格子”
        public Object mParentPoint { get; set; }
        //格子显示对象
        public GameObject mGameObject { get; set; }

        public float mF { get; set; }
        public float mG { get; set; }
        public float mH { get; set; }

        private void ShowMessage()
        {

        }

        private void OnMouseEnter()
        {

        }

        private void OnMouseExit()
        {

        }
        //测试,这里你可以根据自己需求测试
        private void OnMouseDown()
        {
            if (this.type==EA.ObjectType.Cube)
            {
               Person person = PersonManager.Instance.GetPersonByNumber(0);
               person.FindPath(this.baseTransfrom.vector3, Done, Erro);
            }
        }

        private void Done()
        {
            Debug.Log("完成!");
        }
        private void Erro()
        {
            Debug.Log("此路不通!");
        }
    }
    [System.Serializable]
    public class JsonObject
    {
        public static Dictionary<int, GameObject> ODict = new Dictionary<int, GameObject>();
        public int ID;
        public EA.ObjectType type;
        public EA.LayerType layer;
        public int parentCubeID;//0代表没有
        public string message;
        public BaseTransfrom baseTransfrom;

        public JsonObject(Object _object)
        {
            this.ID = _object.ID;
            this.type = _object.type;
            this.layer = _object.layer;
            this.parentCubeID = _object.parentCubeID;
            this.message = _object.message;
            this.baseTransfrom = _object.baseTransfrom;
        }

        public static GameObject GetGameObjectByID(int ID)
        {
            GameObject go = null;
            ODict.TryGetValue(ID, out go);
            return go;
        }
    }

}

测试类Person,请忽略其他无关代码


using DG.Tweening;
using System;
using System.Collections.Generic;
using UnityEngine;
using YsFrame;
using YSFrame;
using Object = YSFrame.Object;

[System.Serializable]
[RequireComponent(typeof(Animation))]
public  class Person: MonoBehaviour,IPerson
{
    private GameManager gameManger;
    Action YsPathOnCompelete;//寻路完成回掉
    Action YsPathErro;//此路不通!
    [Header("[PersonBaseInfo]")]
    [SerializeField]
    private EA.PersonState personState;
    [SerializeField]
    private int _number;
    [SerializeField]
    private string _name;
    [SerializeField]
    private int _age;
    [SerializeField]
    private long _money;
    [SerializeField]
    private long _asset;
    [SerializeField]
    private EA.Sex _sex;
    [SerializeField]
    private EA.Status _status;
    [SerializeField]
    private EA.Bourgeoisie _bourgeoisie;
    [SerializeField]
    private Animator _animator;
    [SerializeField]
    private EA.AnimationState _animationState;
    [SerializeField]
    private Customizer _customizer;
    //存储路径点
    public List<Object> mPathPosList;

    public YSFrame.Object mStartPos;
    public YSFrame.Object mEndPos;
    public int Number
    {
        get
        {
            return _number;
        }

        set
        {
            _number = value;
        }
    }
    public string Name {
        get {
            return _name;
        }
        set {
            _name = value;
        }
    }
    public int Age
    {
        get {
            return _age;
        }
        set {
            _age = value;
        }
    }
    public EA.Sex Sex
    {
        get
        {
            return _sex;
        }
        set
        {
            _sex = value;
        }
    }
    public EA.Bourgeoisie Bourgeoisie
    {
        get
        {
            return _bourgeoisie;
        }
        set
        {
            _bourgeoisie = value;
        }
    }
    public EA.Status Status
    {
        get
        {
            return _status;
        }

        set
        {
            _status = value;
        }
    }
    public Animator Animator
    {
        get
        {
            return _animator;
        }

        set
        {
            _animator = value;
        }
    }
    public long Money
    {
        get
        {
            return _money;
        }

        set
        {
            _money = value;
        }
    }
    public long Asset {
        get
        {
            return _asset;
        }

        set
        {
            _asset = value;
        }
    }
    public EA.AnimationState AnimationState
    {
        get
        {
            return _animationState;
        }

        set
        {
            _animationState = value;
        }
    }
    public Customizer Customizer
    {
        get { return _customizer; }
        set { _customizer = value; }
    }

    public EA.PersonState PersonState
    {
        get
        {
            return this.personState;
        }
        set { personState = value; }
    }

    private int index;//路径下标
    /// <summary>
    /// 转换职业身份
    /// </summary>
    /// <param name="status"></param>
    public void ChangeStatus(EA.Status status)
    {
        if (status == this.Status) return;
        Type sT = Status.GetAttribute();
        Destroy(this.GetComponent(sT));
        this.Status = status;
        Type eT = Status.GetAttribute();
        this.gameObject.AddComponent(eT);
    }
    public  void Die()
    {
        
    }
    /// <summary>
    /// A*寻路
    /// </summary>
    /// <param name="target"></param>
    public void FindPath(Vector3 target,Action OnCompelete, Action ysPathErro)
    {
        if (PersonState == EA.PersonState.Walk)
        {
            transform.DOPause();
        }

        this.YsPathOnCompelete += OnCompelete;
        this.YsPathErro += ysPathErro;
        if (mPathPosList != null)
        {
            mPathPosList.Clear();
        }
        YsPath.GetInsatnce.ClearGrid();
        //网格点对象重新刷新了  需要使用网格来索引到点 mPathPosList存储的点是之前的AStarPoint
        this.mEndPos = YsPath.GetObjectByPoints(target);
        if (this.mStartPos==null)
        {
            this.mStartPos = YsPath.GetObjectByPoints(transform.localPosition);
        }
        mPathPosList = YsPath.GetInsatnce.FindPath(mStartPos, mEndPos);
        if (mPathPosList == null) return;
        if (mPathPosList.Count == 1 && mPathPosList[0] == mEndPos)
        {
            YsPathErro();
            return;
        }
        index = mPathPosList.Count - 1;
        Walk();
    }
    /// <summary>
    /// 播动画
    /// </summary>
    /// <param name="animationState"></param>
    public void PlayAnimation(EA.AnimationState animationState)
    {
        if (animationState == _animationState) return;
        string animationController = animationState.GetAttributeAnimatiomName(0);
        int animationInterger = Int32.Parse( (animationState.GetAttributeAnimatiomName(1)));
        Animator.SetInteger(animationController,animationInterger);
        this.AnimationState = animationState;
        if (animationState == EA.AnimationState.Run) {
           // Run();
        } else if (animationState == EA.AnimationState.Walk) {
            //Walk();
        }else if (animationState == EA.AnimationState.Idle)
        {
          //  Idle();
        }
    }
    public  void Run()
    {
       
    }
    public  void Talk(string message)
    {
      
    }

    public void Walk()
    {
        if (index < 0)
        {
            PersonState = EA.PersonState.Idle;
            YsPathOnCompelete();
        }
        if (mPathPosList != null && mPathPosList.Count >= 1)
        {
            PersonState = EA.PersonState.Walk;
            this.transform.DOLookAt(mPathPosList[index].baseTransfrom.vector3, 0.5f,AxisConstraint.Y);
                this.transform.DOLocalMove(mPathPosList[index].baseTransfrom.vector3+new Vector3(0,2.6f,0), 1f).SetEase(Ease.Flash).OnComplete(() =>
                {
                        mPathPosList.Remove(mPathPosList[index]);
                    if (mPathPosList.Count!=0)
                    {
                        mStartPos = mPathPosList[mPathPosList.Count - 1];
                    }
                        index--;
                       Walk();
                });
        }
    }
    public void Idle()
    {
        this.transform.DOPause();
    }

    void FixedUpdate()
    {
        if (gameManger.gameState==EA.GameState.InGame)
        {
            switch (PersonState)
            {
                case EA.PersonState.Walk:
                   // if(AnimationState==EA.AnimationState.Walk)return;
                   //PlayAnimation(EA.AnimationState.Walk);
                    break;
                case EA.PersonState.Run:
                    break;
                case EA.PersonState.Idle:
                    //if (AnimationState == EA.AnimationState.Idle) return;
                    //PlayAnimation(EA.AnimationState.Idle);
                    break;
            }
        }
    }

    void Awake()
    {
        this.Animator = this.GetComponent<Animator>();
        this._customizer = GetComponent<Customizer>();
        this.gameManger = GameObject.FindGameObjectWithTag("GameController").GetComponent<GameManager>();
    }
}

我并没有采用二维数组构建地图,我使用的是我现有的地图寻路。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_阿松先生

感谢您的支持~

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

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

打赏作者

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

抵扣说明:

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

余额充值