Unity 实现简单 A* 寻路

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18192161/article/details/79262081

OK,A*的算法在网上有很多,当初我书写A*的时候参考的就是网络文章,下面附上链接
http://www.360doc.com/content/16/1201/12/99071_610999046.shtml

根据A*的算法来看,我们需要将地图划分为一个一个格子,然后标记处可行走的区域和不可行走的区域,然后经过计算得到一条两点之间的路径。

首先我们先实现将地图划分为N个格子。
实现方法:
1.在高度100(可设置)的地方超地面投射50*50(可设置),间距为(0.5*0.5)(可设置)的矩阵射线
2.检测射线碰撞体为Ground(10)(可设置),存储改点状态为可行走区域

脚本MapPath:

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

public class MapPath : MonoBehaviour {

    public static MapPath Instance; 

    /// <summary>
    /// 是否绘制Gizmos
    /// </summary>
    public bool IsGizmos = false;

    /// <summary>
    /// 可行走节点
    /// </summary>
    [HideInInspector]
    public List< MapGridInfo> gridItem = new List<MapGridInfo>();
    /// <summary>
    /// 可行走节点名称
    /// </summary>
    [HideInInspector]
    public List<string> gridItemName = new List<string>();
    /// <summary>
    /// 寻找的路径 
    /// </summary>
    private List<PathFinding> pathFindnig = new List<PathFinding>();

    /// <summary>
    /// 检测层
    /// </summary>
    public int DetLayer = 0;
    /// <summary>
    /// 格子尺寸
    /// </summary>
    public Vector2 MapGridSize = new Vector2(1, 1);
    /// <summary>
    /// 格子数量
    /// </summary>
    public Vector2 MapGridNum = new Vector2(100, 100);
    /// <summary>
    /// 射线投放高度
    /// </summary>
    public float DetHeight = 100;

    //private APath Apath;

    private List<MapGridInfo> pathStr = new List<MapGridInfo>();

    /// <summary>
    /// 主线程事件
    /// </summary>
    public static Stack<Action> MainThreadAction = new Stack<Action>();

    void Awake()
    {
        Instance = this;
        GUITools.ResterWindowAction(new Rect(0,150,200,160),delegate(GUIAction action) {
            action.Rect= GUI.Window(action.Id,action.Rect,delegate {

                GUI.Label(new Rect(5,20,80,20),"Start Point:");
                action.Param[0] = GUI.TextField(new Rect(75,20,40,20) ,action.Param[0]);
                action.Param[1] = GUI.TextField(new Rect(125,20,40, 20), action.Param[1]);

                GUI.Label(new Rect(5, 45, 80, 20), "End Point:");
                action.Param[2] = GUI.TextField(new Rect(75, 45, 40, 20), action.Param[2]);
                action.Param[3] = GUI.TextField(new Rect(125, 45, 40, 20), action.Param[3]);

                action.Param[4] = GUI.Toggle(new Rect(5, 70, 50, 20), bool.Parse(action.Param[4]),"IsPathMove").ToString();
                if(bool.Parse(action.Param[4]))
                    action.Param[5] = GUI.TextField(new Rect(5, 95, 190, 20), action.Param[5]);

                if (GUI.Button(new Rect(5, 120, 190, 30), "Find Path"))
                {
                    pathStr.Clear();

                    if (bool.Parse(action.Param[4]))
                    {

                        Actor TestActor = null;
                        GameObject obj = GameObject.Find(action.Param[5]);
                        if (obj != null)
                            TestActor = obj.GetComponent<Actor>();
                        if (TestActor != null)
                            FindPaht(TestActor, new Vector3(float.Parse(action.Param[2]),0, float.Parse(action.Param[3])), null);
                    }
                    else
                    {
                        //List<Vector2> pathPoint = GetPath(GetPos(new Vector2(float.Parse(action.Param[0]), float.Parse(action.Param[1]))), GetPos(new Vector2(float.Parse(action.Param[2]), float.Parse(action.Param[3]))));
                        //for (int i = 0; i < pathPoint.Count; i++)
                            //pathStr.Add(GetGridInfo(GetGridName(pathPoint[i])));
                    }
                }

                GUI.DragWindow();
            },action.Id+ "- A* Path|MapPath");
        },"0","0","0","0","false","Player");

        APath.IsWalk = delegate (Vector2 pos) {
            return IsWalk(pos);
            /*
            MapGridInfo info = GetGridInfo(name);
            if (info != null)
                return info.IsWalk;
            return false;
            */
        };

        APath.IsObstacles = delegate (Vector2 pos1, Vector2 pos2)
        {
            Vector3 newPos1 = new Vector3(pos1.x * MapGridSize.x, 0, pos1.y * MapGridSize.y);
            Vector3 newPos2 = new Vector3(pos2.x * MapGridSize.x, 0, pos2.y * MapGridSize.y);

            return IsObstaclesTwoPoint(newPos1, newPos2);
        };
    }

    void Update()
    {
        while (MainThreadAction.Count > 0) MainThreadAction.Pop()();

        for (int i = 0; i < pathFindnig.Count; i++)
            pathFindnig[i].OnTick();
    }

    void OnDrawGizmos()
    {
        if (Instance == null)
            Instance = this;
        if (IsGizmos)
        {
            OnDrawPoint();
        }
    }

    /// <summary>
    /// 绘制给子
    /// </summary>
    void OnDrawPoint()
    {
        foreach (var data in gridItem)
        {
            if (!data.IsWalk) return;
            if (pathStr.Contains(data))
            {
                data.DrawGizmos(delegate { Gizmos.color = Color.yellow; });
            }
            else
                data.DrawGizmos();
        }
    }

    /// <summary>
    /// 是否可以行走
    /// </summary>
    /// <param name="pos"></param>
    /// <returns></returns>
    public bool IsWalk(Vector3 pos)
    {
        string name = GetGridName(GetPos(pos));
        if (gridItemName.Contains(name))
            return true;
        return false;
    }

    /// <summary>
    /// 是否可以行走
    /// </summary>
    /// <param name="pos"></param>
    /// <returns></returns>
    public bool IsWalk(Vector2 pos)
    {
        string name = GetGridName(pos.x, pos.y);
        if (gridItemName.Contains(name))
            return true;
        return false;
    }


    /// <summary>
    /// 生成地图给子
    /// </summary>
    public void DetMapGrid()
    {
        gridItem.Clear();
        gridItemName.Clear();
        for (int i = 0; i < MapGridNum.x; i++)
        {
            //yield return new WaitForSeconds(0.02f);
            for (int j = 0; j < MapGridNum.y; j++)
            {
                //yield return new WaitForSeconds(0.02f);
                Vector3 pos = new Vector3(MapGridSize.x * i + MapGridSize.x / 2f, DetHeight, MapGridSize.y * j + MapGridSize.y / 2f);
                MapGridInfo info = new MapGridInfo(pos, i + "-" + j);
                if (info.IsWalk)
                {
                    gridItemName.Add(info.GridName);
                    gridItem.Add(info);
                }
            }
        }
        Debug.Log("地图配置完毕....");
    }

    /// <summary>
    /// 查找路径
    /// </summary>
    /// <param name="actor"></param>
    /// <param name="end"></param>
    /// <param name="OnFinsh"></param>
    public void FindPaht(Actor actor,Vector3 end,Action<float> OnFinsh)
    {
        if (actor != null)
        {
            pathStr.Clear();
            Vector2 actorPos = GetPos(actor.position);
            Vector2 endPos = GetPos(end);
            if (actorPos == endPos) return;
            if (!gridItemName.Contains(GetGridName(endPos))) return;

            actor.OnPathFinshEvent = OnFinsh;
            actor.OnFindPathFinshEvent = delegate(Actor actor1,List<Vector2> path){
                OnFindPathFinsh(actor1, path, actor1.OnPathFinshEvent);
            };

            if (!IsObstaclesTwoPoint(actor.position, end))
            {
                OnFindPathFinsh(actor, new List<Vector2>() { GetPos(end) },OnFinsh);
                //info.Add(GetGridInfo(GetGridName(endPos)));
            }
            else
            {
                ProfilerTools.BeginSample("A* Path", delegate
                {
                    APath.FindPath(actor, actorPos, endPos);
                   //GetPath(actor, actorPos, endPos); ;
                });
            }
        }
    }

    /// <summary>
    /// 路径查找结束
    /// </summary>
    /// <param name="actor"></param>
    /// <param name="path"></param>
    /// <param name="OnFinsh"></param>
    public void OnFindPathFinsh(Actor actor, List<Vector2> path, Action<float> OnFinsh)
    {

        List<MapGridInfo> info = new List<MapGridInfo>();
        for (int i = 0; i < path.Count; i++)
            pathStr.Add(GetGridInfo(GetGridName(path[i])));
        info.AddRange(pathStr);

        PathFinding pathF = GetPathFinding(actor);
        if (pathF != null)
        {
            pathF.ChangePath(info);
            return;
        }

        PathFinding pf = new PathFinding(actor, info);
        pf.OnFinsh = delegate (float time)
        {
            pathFindnig.Remove(pf);
            if (OnFinsh != null)
                OnFinsh(time);
        };
        pathFindnig.Add(pf);
    }
    /// <summary>
    /// 两点之间是否可直接通行
    /// </summary>
    /// <param name="pos1"></param>
    /// <param name="pos2"></param>
    /// <returns></returns>
    public bool IsObstaclesTwoPoint(Vector3 pos1,Vector3 pos2)
    {
        Vector3 dir = pos1 - pos2;
        float dis = Vector3.Distance(pos1,pos2);
        float num = dis / MapGridSize.x;
        bool isObstacle = false;
        for (int i = 1; i < num; i++)
        {
            Vector3 detPos = pos2 + dir.normalized * (MapGridSize.x*i);
            if (!IsWalk(detPos))
                isObstacle = true;
        }
        return isObstacle;
    }

    /// <summary>
    /// 获取路径
    /// </summary>
    /// <param name="actor"></param>
    /// <returns></returns>
    public PathFinding GetPathFinding(Actor actor)
    {
        for (int i = 0; i < pathFindnig.Count; i++)
        {
            if (pathFindnig[i].Actor == actor)
                return pathFindnig[i];
        }
        return null;
    }

    /// <summary>
    /// 获取格子信息
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public MapGridInfo GetGridInfo(string name)
    {

        for (int i = 0; i < gridItem.Count; i++)
        {
            if (gridItem[i].GridName.Equals(name))
                return gridItem[i];
        } 
        return null;
    }

    /// <summary>
    /// 坐标转换
    /// </summary>
    /// <param name="gridPos"></param>
    /// <returns></returns>
    public Vector2 GetPos(Vector2 gridPos)
    {
        return new Vector2(((int)(gridPos.x / MapGridSize.x)), ((int)(gridPos.y / MapGridSize.y)));
    }

    /// <summary>
    /// 坐标转换
    /// </summary>
    /// <param name="gridPos"></param>
    /// <returns></returns>
    public Vector2 GetPos(Vector3 gridPos)
    {
        return new Vector2(((int)(gridPos.x / MapGridSize.x)), ((int)(gridPos.z / MapGridSize.y)));
    }

    /// <summary>
    /// 获取名称
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    public string GetGridName(float x,float y)
    {
        return x+ "-" + y;
    }
    /// <summary>
    /// 获取名称
    /// </summary>
    /// <param name="gridPos"></param>
    /// <returns></returns>
    public string GetGridName(Vector3 gridPos)
    {
        return gridPos.x + "-" + gridPos.z;
    }
    /// <summary>
    /// 获取名称
    /// </summary>
    /// <param name="gridPos"></param>
    /// <returns></returns>
    public string GetGridName(Vector2 gridPos)
    {
        return gridPos.x + "-" + gridPos.y;
    }
}

这个类的主要功能:
1.在编辑器中绘制并显示mesh

  /// <summary>
  /// 生成地图给子
  /// </summary>
  public void DetMapGrid()
  {
      gridItem.Clear();
      gridItemName.Clear();
      for (int i = 0; i < MapGridNum.x; i++)
      {
          //yield return new WaitForSeconds(0.02f);
          for (int j = 0; j < MapGridNum.y; j++)
          {
              //yield return new WaitForSeconds(0.02f);
              Vector3 pos = new Vector3(MapGridSize.x * i + MapGridSize.x / 2f, DetHeight, MapGridSize.y * j + MapGridSize.y / 2f);
              MapGridInfo info = new MapGridInfo(pos, i + "-" + j);
              if (info.IsWalk)
              {
                  gridItemName.Add(info.GridName);
                  gridItem.Add(info);
              }
          }
      }
      Debug.Log("地图配置完毕....");
  }

2.查找路径

   /// <summary>
    /// 查找路径
    /// </summary>
    /// <param name="actor"></param>
    /// <param name="end"></param>
    /// <param name="OnFinsh"></param>
    public void FindPaht(Actor actor,Vector3 end,Action<float> OnFinsh)
    {
        if (actor != null)
        {
            pathStr.Clear();
            Vector2 actorPos = GetPos(actor.position);
            Vector2 endPos = GetPos(end);
            if (actorPos == endPos) return;
            if (!gridItemName.Contains(GetGridName(endPos))) return;

            actor.OnPathFinshEvent = OnFinsh;
            actor.OnFindPathFinshEvent = delegate(Actor actor1,List<Vector2> path){
                OnFindPathFinsh(actor1, path, actor1.OnPathFinshEvent);
            };

            if (!IsObstaclesTwoPoint(actor.position, end))
            {
                OnFindPathFinsh(actor, new List<Vector2>() { GetPos(end) },OnFinsh);
                //info.Add(GetGridInfo(GetGridName(endPos)));
            }
            else
            {
                ProfilerTools.BeginSample("A* Path", delegate
                {
                    APath.FindPath(actor, actorPos, endPos);
                   //GetPath(actor, actorPos, endPos); ;
                });
            }
        }
    }

类:MapGridInfo 格子的详细信息

[SerializeField]
[System.Serializable]
public class MapGridInfo
{
    /// <summary>
    /// 格子名称
    /// </summary>
    public string GridName;
    /// <summary>
    /// 格子坐标
    /// </summary>
    public Vector3 GridPos;
    /// <summary>
    /// 是否可以行走
    /// </summary>
    public bool IsWalk;
    /// <summary>
    /// 网格信息
    /// </summary>
    private Mesh _meshInfo;
    public Mesh MeshInfo {
        get {
            if (_meshInfo == null)
            {
                IsWalk = Ray();
                SetMesh();
            }
            return _meshInfo;
        }
    }
    /// <summary>
    /// 绘制高度
    /// </summary>
    public float Height;
    /// <summary>
    /// 颜色
    /// </summary>
    public Color GizmosColor;

    public MapGridInfo(Vector3 gridPos,string gridName)
    {
        GridName = gridName;
        GridPos = gridPos;
        IsWalk = Ray();
        SetMesh();
    }
    /// <summary>
    /// 设置网格
    /// </summary>
    void SetMesh()
    {
        Mesh mesh = new Mesh();
        List<Vector3> vertices = new List<Vector3>();
        vertices.Add(new Vector3(GridPos.x + GetSize.x / 2, Height, GridPos.z + GetSize.y / 2));
        vertices.Add(new Vector3(GridPos.x + GetSize.x / 2, Height, GridPos.z - GetSize.y / 2));
        vertices.Add(new Vector3(GridPos.x - GetSize.x / 2, Height, GridPos.z - GetSize.y / 2));
        vertices.Add(new Vector3(GridPos.x - GetSize.x / 2, Height, GridPos.z + GetSize.y / 2));
        mesh.vertices = vertices.ToArray();

        List<int> tri = new List<int>();
        tri.Add(0);
        tri.Add(1);
        tri.Add(2);
        tri.Add(0);
        tri.Add(2);
        tri.Add(3);
        mesh.triangles = tri.ToArray();
        mesh.RecalculateBounds();
        mesh.RecalculateNormals();
        _meshInfo = mesh;
    }
    /// <summary>
    /// 获取尺寸
    /// </summary>
    Vector2 GetSize
    {
        get{ return new Vector2(MapPath.Instance.MapGridSize.x - MapPath.Instance.MapGridSize.x*0.1f, MapPath.Instance.MapGridSize.y - MapPath.Instance.MapGridSize.y*0.1f); }
    }

    /// <summary>
    /// 绘制格子
    /// </summary>
    /// <param name="OnChangeColor"></param>
    public void DrawGizmos(System.Action OnChangeColor = null)
    {
        Gizmos.color = GizmosColor;
        if (OnChangeColor != null)
            OnChangeColor();
        Gizmos.DrawMesh(MeshInfo);
    }
    /// <summary>
    /// 投送射线
    /// </summary>
    /// <returns></returns>
    private bool Ray()
    {
        RaycastHit hitInfo;
        if (Physics.Raycast(GridPos, Vector3.down, out hitInfo, MapPath.Instance.DetHeight + 50))
        {
            if (hitInfo.collider.gameObject.layer == MapPath.Instance.DetLayer)
            {
                GizmosColor = Color.green;
                Height = hitInfo.point.y + 0.1f;
                return true;
            }
        }
        GizmosColor = Color.red;
        return false;
    }

}

主要实现功能:
1.存储格子的相关信息,比如坐标,名称,是否可行走,mesh信息等
2.投放射线检测目标是否可以行走
3.绘制mesh在编辑器进行显示

类:PathFinding

/// <summary>
/// 路径移动
/// </summary>
public class PathFinding
{
    /// <summary>
    /// 角色
    /// </summary>
    public Actor Actor { get; private set; }
    /// <summary>
    /// 查找的路径
    /// </summary>
    public List<MapGridInfo> PathPoint { get; private set; }
    /// <summary>
    /// 当前点
    /// </summary>
    public MapGridInfo CurPoint { get; private set; }
    /// <summary>
    /// 时间
    /// </summary>
    private float RunTime = 0;
    /// <summary>
    /// 结束事件
    /// </summary>
    public Action<float> OnFinsh { get; set; }

    public PathFinding(Actor actor,List<MapGridInfo> pathPoint) {
        Actor = actor;
        PathPoint = pathPoint;
        CurPoint = GetNetPoint;
    }

    public void ChangePath(List<MapGridInfo> pathPoint)
    {
        PathPoint = pathPoint;
        CurPoint = GetNetPoint;
    }
    /// <summary>
    /// 获取下一个点
    /// </summary>
    MapGridInfo GetNetPoint {
        get {
            if (PathPoint.Count > 0)
            {
                MapGridInfo mi = PathPoint[0];
                PathPoint.RemoveAt(0);
                return mi;
            }
            if (OnFinsh != null)
                OnFinsh(RunTime);
            return null;
        }
    }

    /// <summary>
    /// 循环事件
    /// </summary>
    public void OnTick()
    {
        if (CurPoint != null)
        {
            RunTime += Time.deltaTime;
            Actor.SetPathMove(CurPoint.GridPos,0.1f,delegate {
                CurPoint = GetNetPoint;
                if (CurPoint == null)
                    Actor.SetIdleState();
            },delegate {
                if (OnFinsh != null)
                    OnFinsh(RunTime);
            } );
        }
    }

}

此类的功能:
1.主要实现控制角色跟随路径进行移动

A* 的主要算法类:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEditor.VersionControl;
using UnityEngine;


/// <summary>
/// A*寻路
/// </summary>
public class APath
{
    public static Stack<APath> Pool = new Stack<APath>();
    public static APath Create()
    {
        if (Pool.Count < 1)
            return new APath();
        return Pool.Pop();
    }

    public static void FindPath(Actor actor,Vector2 start, Vector2 end)
    {
        APath aPath = APath.Create();
        aPath.SetStartPoint(start);
        aPath.SetEndPoint(end);
        ThreadPool.QueueUserWorkItem(new WaitCallback(aPath.GetPath),actor);
    }

    private List<APoint> Close = new List<APoint>();
    private List<APoint> Open = new List<APoint>();

    //private MapGridData gridData;
    /*
    public APath(MapGridData _gridData)
    {
        gridData = _gridData;
    }*/

    public Vector2 GridSize = Vector2.one;

    public Vector2 startPoint;
    public Vector2 endPoint;

    public static Func<Vector2, bool> IsWalk;
    public static Func<Vector2, Vector2, bool> IsObstacles;
    /*
    public APath(Func<Vector2, bool> isWalk, Func<Vector2, Vector2, bool> isObstacles)
    {
        IsWalk = isWalk;
        IsObstacles = isObstacles;
    }*/

    public void SetStartPoint(Vector2 start)
    {
        startPoint = new Vector2((int)start.x, (int)start.y);
    }

    public void SetEndPoint(Vector2 end)
    {
        endPoint = new Vector2((int)end.x, (int)end.y);
    }

    /// <summary>
    /// 获取路径
    /// </summary>
    /// <param name="start"></param>
    /// <param name="end"></param>
    /// <returns></returns>
    public void GetPath(object state)
    {
        Actor actor = (Actor)state;
        //初始化操作
        //startPoint = new Vector2((int)start.x, (int)start.y);
        //endPoint = new Vector2((int)end.x, (int)end.y);
        APoint.Clear(ref Close);
        APoint.Clear(ref Open);
        //Close.Clear();
        //Open.Clear();
        APoint curPoint = APoint.Create();
        curPoint.Point = startPoint;
        curPoint.G = 0;
        curPoint.H = 0;
        if (curPoint == null)
            Console.WriteLine("111");
        do
        {
            if (Open.Contains(curPoint))
                Open.Remove(curPoint);
            Close.Add(curPoint);
            if (IsEnd(curPoint))
                break;
            if (Open != null)
            {
                GetAround(curPoint);
                APoint nextPoint = null;
                float minF = -1;
                for (int i = 0; i < Open.Count; i++)
                {
                    //mimF == -1 表示F没有进行初始化,第一次循环进行初始化
                    //Debug.Log(string.Format("Point:{0} G:{1} H:{2} F:{3}", Open[i].Point, Open[i].G, Open[i].H, Open[i].F));
                    if (minF == -1)
                    {
                        minF = Open[i].F;
                        nextPoint = Open[i];
                        continue;
                    }

                    //获取F最小的点进行赋值
                    if (Open[i].F < minF)
                    {
                        minF = Open[i].F;
                        nextPoint = Open[i];
                    }
                }
                if (nextPoint == null)
                    Console.WriteLine("111111");
                //清空open表
                curPoint = nextPoint;
            }

        } while (Open.Count > 0);


        List<Vector2> pointList = new List<Vector2>();
        if (curPoint != null)
        {
            APoint prePoint = curPoint;
            while (true)
            {
                if (prePoint.prePoint == null)
                    break;
                pointList.Add(prePoint.Point);
                prePoint = prePoint.prePoint;
            }
        }

        MapPath.MainThreadAction.Push(delegate {
            actor.OnFindPathFinshEvent(actor, ReversePoint(pointList));
            OnFinsh();
        });

    }


    /// <summary>
    /// 反转列表
    /// </summary>
    /// <param name="point"></param>
    /// <returns></returns>
    public List<Vector2> ReversePoint(List<Vector2> point)
    {
        List<Vector2> newPoint = new List<Vector2>();
        for (int i = point.Count - 1; i >= 0; i--)
            newPoint.Add(point[i]);
        return newPoint;
    }

    /// <summary>
    /// 获取点周围数据
    /// </summary>
    /// <param name="point"></param>
    /// <returns></returns>
    float x = 2f;
    public void GetAround(APoint point)
    {

        //获取左右上下八个方位的点
        Vector2 top = new Vector2(point.Point.x, point.Point.y + GridSize.y);
        if (IsAddOpen(top, IsWalk))
        {
            APoint apoint = APoint.Create();
            apoint.prePoint = point;
            apoint.Point = top;
            apoint.G = point.G + 1;
            apoint.H = GetH(top);
            Open.Add(apoint);
        }

        Vector2 down = new Vector2(point.Point.x, point.Point.y - GridSize.y);
        if (IsAddOpen(down, IsWalk))
        {
            APoint apoint = APoint.Create();
            apoint.prePoint = point;
            apoint.Point = down;
            apoint.G = point.G + 1;
            apoint.H = GetH(down);
            Open.Add(apoint);
        }

        Vector2 left = new Vector2(point.Point.x - GridSize.x, point.Point.y);
        if (IsAddOpen(left, IsWalk))
        {
            APoint apoint = APoint.Create();
            apoint.prePoint = point;
            apoint.Point = left;
            apoint.G = point.G + 1;
            apoint.H = GetH(left);
            Open.Add(apoint);
        }

        Vector2 right = new Vector2(point.Point.x + GridSize.x, point.Point.y);
        if (IsAddOpen(right, IsWalk))
        {
            APoint apoint = APoint.Create();
            apoint.prePoint = point;
            apoint.Point = right;
            apoint.G = point.G + 1;
            apoint.H = GetH(right);
            Open.Add(apoint);
        }

        Vector2 topLeft = new Vector2(point.Point.x - GridSize.x, point.Point.y + GridSize.y);
        if (IsAddOpen(topLeft, IsWalk))
        {
            APoint apoint = APoint.Create();
            apoint.prePoint = point;
            apoint.Point = topLeft;
            apoint.G = point.G + x;
            apoint.H = GetH(topLeft);
            Open.Add(apoint);
        }

        Vector2 topRight = new Vector2(point.Point.x + GridSize.x, point.Point.y + GridSize.y);
        if (IsAddOpen(topRight, IsWalk))
        {
            APoint apoint = APoint.Create();
            apoint.prePoint = point;
            apoint.Point = topRight;
            apoint.G = point.G + x;
            apoint.H = GetH(topRight);
            Open.Add(apoint);
        }

        Vector2 downLeft = new Vector2(point.Point.x - GridSize.x, point.Point.y - GridSize.y);
        if (IsAddOpen(downLeft, IsWalk))
        {
            APoint apoint = APoint.Create();
            apoint.prePoint = point;
            apoint.Point = downLeft;
            apoint.G = point.G + x;
            apoint.H = GetH(downLeft);
            Open.Add(apoint);
        }

        Vector2 downRight = new Vector2(point.Point.x + GridSize.x, point.Point.y - GridSize.y);
        if (IsAddOpen(downRight, IsWalk))
        {
            APoint apoint = APoint.Create();
            apoint.prePoint = point;
            apoint.Point = downRight;
            apoint.G = point.G + x;
            apoint.H = GetH(downRight);
            Open.Add(apoint);
        }
    }


    public int GetH(Vector2 point)
    {
        Vector2 offset = endPoint - point;
        int H = (int)(Math.Abs(offset.x) + Math.Abs(offset.y));

        return H;
    }

    public bool IsEnd(APoint point)
    {
        // 如果是结束为止 返回null、
        if (point.Point.x == endPoint.x && point.Point.y == endPoint.y)
            return true;
        return false;
    }

    /// <summary>
    /// 是否在关闭列表中
    /// </summary>
    /// <param name="point"></param>
    /// <returns></returns>
    public bool IsClose(Vector2 point)
    {
        for (int i = 0; i < Close.Count; i++)
        {
            if (Close[i].Point.x == point.x&&Close[i].Point.y==point.y)
                return true;
        }
        return false;
    }

    /// <summary>
    /// 是否在检测列表中
    /// </summary>
    /// <param name="point"></param>
    /// <returns></returns>
    public bool IsOpen(Vector2 point)
    {
        for (int i = 0; i < Open.Count; i++)
        {
            if (Open[i].Point.x == point.x && Open[i].Point.y == point.y)
                return true;
        }
        return false;
    }

    /// <summary>
    /// 是否添加进检测列表中
    /// </summary>
    /// <param name="point"></param>
    /// <returns></returns>
    public bool IsAddOpen(Vector2 point,Func<Vector2,bool> isWalk)
    {
        //可行走 不在关闭列表 不在打开列表
        if (isWalk(point) && !IsClose(point) && !IsOpen(point))
        {
            return true;
        }
        return false;
    }

    public void OnFinsh()
    {
        Pool.Push(this);
    }

}

public class APoint
{
    private static Stack<APoint> Pool = new Stack<APoint>();

    private APoint() { }

    public Vector2 Point;
    public APoint prePoint;
    public float G; //到起点的距离
    public int H; //到终点的距离
    public float F //消耗
    {
        get
        {
            return G + H;
        }
    }

    public void Close()
    {
        Point = Vector2.zero;
        prePoint = null;
        G = 0;
        H = 0;
        Pool.Push(this);
    }

    public static void Clear(ref List<APoint> aPoint)
    {
        for (int i = 0; i < aPoint.Count; i++)
            aPoint[i].Close();
        aPoint.Clear();
    }

    public static APoint Create()
    {
        if (Pool.Count < 1)
            return new APoint();
        return Pool.Pop();
    }
}

此类初始话时,需要提供三个参数,玩家,其实目标和结束目标。
感觉这个东西只能自己研究看看,在真正的游戏项目中还没办法使用,因为,优化效果太差了,随便看看吧,过完年,在考虑怎么进行优化…
最终结果
这里写图片描述

寻路: 中间色块都用屎黄色进行标识,看不清楚我画了一条红线

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_18192161/article/details/79262081
今日推荐