参考视频
//节点类
//节点类型枚举
public enum NodeTyp
{
//可用格子
Able,
//不可用格子
Unable
}
public class AStartNode
{
//格子坐标
public int x;
public int y;

//寻路消耗
public float f;

//起点距离
public float g;
//终点距离
public float h;

//父对象
public AStartNode father;
//格子类型
public NodeTyp type;

public AStartNode(int x,int y, NodeTyp type)
{
    this.x = x;
    this.y = y;
    this.type = type;
}

}

//单例基类
public class BaseManager
where T:new()//限定T有一个无参数的构造函数
{
private static T instence;

public static T Instence
{
    get
    {
        if (instence == null)
            instence = new T();
        return instence;
    }
}

}

//管理器类(单例)
public class AStartManager :BaseManager
{
/*private static AStartManager instence;
public static AStartManager Instence
{
get
{
if (instence == null)
instence = new AStartManager();
return instence;
}
}
*/
//地图大小
private int mapw;
private int maph;
//所有格子容器
public AStartNode[,] nodes;
//开启类表
private List openList = new List();
//关闭类表
private List closeList = new List();
///


/// 初始化地图信息
///

///
///
public void InitMapInfo(int mapw, int maph)
{
this.mapw = mapw;
this.maph = maph;
nodes = new AStartNode[mapw, maph];
for (int i = 0; i < mapw; i++)
{
for (int j = 0; j < maph; j++)
{
//格子20%概率为阻挡
AStartNode node = new AStartNode(i, j, Random.Range(0, 101) < 20 ? NodeTyp.Unable : NodeTyp.Able);
nodes[i, j] = node;
}
}
}

/// <summary>
/// 寻路方法
/// </summary>
/// <param name="startPos"></param>
/// <param name="endPos"></param>
/// <returns></returns>
public List<AStartNode> FindPath(Vector2 startPos, Vector2 endPos)
{

    /*/判断传入顶点是否合法*/
    //1.1传入顶点噪mapz范围内
    if (startPos.x < 0 || startPos.x >= mapw || startPos.y < 0 || startPos.y >= maph
       || endPos.x < 0 || endPos.x >= mapw || endPos.y < 0 || endPos.y >= maph)
    {
        Debug.Log("OutRange");
        return null;
    }
    AStartNode start = nodes[(int)startPos.x, (int)startPos.y];
    AStartNode end = nodes[(int)endPos.x, (int)endPos.y];
    //2.传入顶点不为阻挡
    //不合法则返回null
    if (start.type == NodeTyp.Unable ||
       end.type == NodeTyp.Unable)
    {
        Debug.Log("非法位置");
        return null;
    }

    //清空上一次相关数据,避免影响此次计算

    //清空开始/关闭类表
    openList.Clear();
    closeList.Clear();

    //把开始点放入关闭类表中
    start.father = null;
    start.g = 0;
    start.h = 0;
    start.f = 0;
    closeList.Add(start);
    while (true)
    {
        //从起点开始寻找周围的点
        //左上
        FindNearlyNodeToOpenList(start.x - 1, start.y - 1, 1.4f, start, end);
        //上
        FindNearlyNodeToOpenList(start.x, start.y - 1, 1f, start, end);
        //右上
        FindNearlyNodeToOpenList(start.x + 1, start.y - 1, 1.4f, start, end);
        //左
        FindNearlyNodeToOpenList(start.x - 1, start.y, 1f, start, end);
        //右
        FindNearlyNodeToOpenList(start.x + 1, start.y, 1f, start, end);
        //左下
        FindNearlyNodeToOpenList(start.x - 1, start.y + 1, 1.4f, start, end);
        //下
        FindNearlyNodeToOpenList(start.x, start.y + 1, 1f, start, end);
        //右下
        FindNearlyNodeToOpenList(start.x + 1, start.y + 1, 1.4f, start, end);
        //判断周围的点是否合法,是否在开启或关闭类表,不是则放入开始了表

        //死路判定:开启类表为空时中非那不可达
        if (openList.Count == 0)
        {
            Debug.Log("死路");
            return null;
        }
        //选出开启类表中寻路消耗最小的点
        openList.Sort(SortOpenList);//排序后openList[0]为f值最小的点
                                    //放入关闭类表中然后从开始了表中移除
        closeList.Add(openList[0]);
        //找到的点作为下一次寻找开始的起点
        start = openList[0];
        openList.RemoveAt(0);
        //如果这个点是终点则返回出去
        //不是终点则继续寻找
        if (start == end)
        {
            List<AStartNode> path = new List<AStartNode>();
            path.Add(end);
            while (end.father != null)
            {
                path.Add(end.father);
                end = end.father;
            }
            path.Reverse();
            return path;
        }

    }
}
/// <summary>
/// 排序函数
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
private int SortOpenList(AStartNode a, AStartNode b)
{
    if (a.f > b.f)
        return 1;
    else if (a.f == b.f)
        return 1;
    else
        return -1;
}
/// <summary>
/// 把临近点放入开启类表中的函数
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
private void FindNearlyNodeToOpenList(int x, int y, float g, AStartNode fatherNode, AStartNode endNode)
{
    //边界判定
    if (x < 0 || x >= mapw ||
        y < 0 || y >= maph)
        return;
    //在map范围内在取点
    AStartNode node = nodes[x, y];
    if (node == null || node.type == NodeTyp.Unable
        || openList.Contains(node) || closeList.Contains(node))
        return;

    //计算f值:f=g+h
    //记录父对象
    node.father = fatherNode;
    //计算g(距离起点距离)值:父对象里欠点距离+距离父对象距离
    node.g = fatherNode.g + g;
    //计算h值(距离终点距离):曼哈顿街区算法二维坐标差值
    node.h = Mathf.Abs(endNode.x - node.x) + Mathf.Abs(endNode.y - node.y);
    node.f = node.g + node.h;
    //通过验证则存入开始了表中
    openList.Add(node);
}

}



//测试脚本
public class TextA : MonoBehaviour
{
public int beginX = -2;
public int beginY = -2;

public int offSetX = 2;
public int OffSetY = 2;

public int mapW = 5;
public int mapY = 5;

public Material bnary;
public Material start;
public Material path;
public Material normal;

//存储格子容器(x_y,GameObject)
private Dictionary<string, GameObject> cubes = new Dictionary<string, GameObject>();

private Vector2 beginPos = Vector2.right * -1;
private Vector2 endPos;

//存储路径节点
List<AStartNode> pathList = new List<AStartNode>();

// Start is called before the first frame update
void Start()
{
    AStartManager.Instence.InitMapInfo(mapW, mapY);
    for (int i = 0; i < mapW; i++)
    {
        for (int j = 0; j < mapY; j++)
        {
            GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
            obj.transform.position = new Vector3(beginX + i * offSetX, beginY + j * OffSetY, 0);
            obj.name = i + "_" + j;
            cubes.Add(obj.name, obj);
            //判断格子是否阻挡
            AStartNode node = AStartManager.Instence.nodes[i, j];
            if(node.type == NodeTyp.Unable)
            {
                obj.GetComponent<MeshRenderer>().material= bnary ;
                Debug.Log("Br");
            }
        }
    }
}

// Update is called once per frame
void Update()
{
    if(Input.GetMouseButtonDown(0))
    {
        //射线检测返回值
        RaycastHit hit;
        //相机视角从鼠标位置发出的射线
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        //射线检测,检测到物体返回true
        if (Physics.Raycast(ray, out hit, 1000))
        {
            //得到点击到的立方体
            //hit.collider.gameObject;
            //记录开始点与结束点
            if(beginPos == Vector2.right*-1)
            {
                //清理上一次路径
                if (pathList != null)
                {
                    for (int i = 0; i < pathList.Count; i++)
                    {
                        cubes[pathList[i].x + "_" + pathList[i].y].GetComponent<MeshRenderer>().material = normal;
                    }
                }

                string[] str = hit.collider.gameObject.name.Split('_');
                beginPos = new Vector2(int.Parse(str[0]), int.Parse(str[1]));
                hit.collider.gameObject.GetComponent<MeshRenderer>().material = start;
            }
            else
            {
                string[] str = hit.collider.gameObject.name.Split('_');
                endPos = new Vector2(int.Parse(str[0]), int.Parse(str[1]));
                //hit.collider.gameObject.GetComponent<MeshRenderer>().material = end;

                pathList = AStartManager.Instence.FindPath(beginPos, endPos);
                if(pathList !=null)
                {
                    for (int i = 0; i < pathList.Count; i++)
                    {
                        cubes[pathList[i].x + "_" + pathList[i].y].GetComponent<MeshRenderer>().material = path;
                    }
                }
                //清除开始点
                beginPos = Vector2.right * -1;
            }
        }
    }
}

}