A星寻路学习记录

来源:互联网 发布:ubuntu默认账号密码 编辑:程序博客网 时间:2024/06/07 04:47

//节点
public class Node {

//节点位置public Vector3 position;//在地图中的X轴位置下标public int indexX;//在地图中的Z轴位置下标public int indexZ;//该节点是否可以行走public bool canWalk;//行走代价public float gCost;//距离目标的代价public float hCost;public float fCost { get { return gCost + hCost; } }//父节点 方便回溯路径public Node parent;public Node(Vector3 position, int indexX, int indexZ, bool canWalk){    this.position = position;    this.indexX = indexX;    this.indexZ = indexZ;    this.canWalk = canWalk;}

}

public class Grid : MonoBehaviour {

//地图 储存所有的节点信息public Node[,] maps;//地图的长和宽public float mapSizeX;public float mapSizeZ;//每一个节点的大小 public float nodeSize;//地图长宽各占几个节点public int countX;public int countZ;//障碍物层public LayerMask canNotWalk;public static Grid instance;public List<Node> path;public void Awake(){    instance = this;    Init();}//初始化 生成地图public void Init(){    //地图大小除以节点大小 算出个数    countX = Mathf.CeilToInt(mapSizeX / nodeSize);    countZ = Mathf.CeilToInt(mapSizeZ / nodeSize);    //初始化数组    maps = new Node[countX, countZ];    //地图赋值    for (int x = 0; x < countX; x++)    {        for (int z = 0; z < countZ; z++)        {            float posX = (this.transform.position.x - mapSizeX / 2) + nodeSize *  (x  + 0.5f);            float posY = this.transform.position.y;            float posZ = (this.transform.position.z - mapSizeZ / 2) + nodeSize * (z + 0.5f);            Vector3 nodePos = new Vector3(posX, posY, posZ);            bool canWalk = CheckNodeCanWalk(nodePos);            Node node = new Node(nodePos, x, z, canWalk);            maps[x, z] = node;        }    }}//检查节点是否可以行走public bool CheckNodeCanWalk(Vector3 nodePos){    return !Physics.CheckSphere(nodePos, nodeSize / 2, canNotWalk);}public void OnDrawGizmos(){    if(maps != null)    {        //画出地图        foreach (Node node in maps)        {                if( path.Contains(node))                {                    Gizmos.color = Color.black;                    Gizmos.DrawCube(node.position, Vector3.one * nodeSize * 0.8f);                }                else                {                    if (node.canWalk == true)                    {                        Gizmos.color = Color.gray;                        Gizmos.DrawCube(node.position, Vector3.one * nodeSize * 0.8f);                    }                    else                    {                        Gizmos.color = Color.red;                        Gizmos.DrawCube(node.position, Vector3.one * nodeSize * 0.8f);                    }                }        }    }}//通过一个位置获取一个节点信息public Node GetNodeFromVector3(Vector3 pos){    Node result = maps[0,0];    float mixDistance;    mixDistance = Vector3.Distance(pos, maps[0, 0].position);    for (int x = 0; x < countX; x++)    {        for (int z = 0; z < countZ; z++)        {            float distance = Vector3.Distance(pos, maps[x, z].position);            if(distance < mixDistance)            {                mixDistance = distance;                result = maps[x, z];            }        }    }    return result;}//通过一个节点获取周围8个节点的方法public List<Node> GetNeighbourNode(Node node){    List<Node> list = new List<Node>();    for (int x = -1; x <= 1; x++)    {        for (int z = -1; z <= 1; z++)        {            if (x == 0 && z == 0) continue;            int indexX = node.indexX + x;            int indexZ = node.indexZ + z;            if (indexX >= 0 && indexX < countX && indexZ >= 0 && indexZ < countZ)                list.Add(maps[indexX, indexZ]);        }    }    return list;}

}

public class AIPath : MonoBehaviour {

//目标点public GameObject target;//存放路径public List<Node> path = new List<Node>();// Update is called once per framevoid Update () {    FindingPath(this.transform.position, target.transform.position);}//寻路void FindingPath(Vector3 startPos, Vector3 endPos){    //查找开始点和终点所处于的节点    Node startNode = Grid.instance.GetNodeFromVector3(startPos);    Node endNode = Grid.instance.GetNodeFromVector3(endPos);    //开关列表 开列表存放待搜索的所有节点 闭列表存放所有不需要计算的节点(例如 障碍物)    List<Node> openList = new List<Node>();    List<Node> closeList = new List<Node>();    //初始点作为待搜索的第一个点  开始搜索    openList.Add(startNode);    while(openList.Count > 0)    {        //以待搜索的第一个为起始点         Node currentNode = openList[0];        for (int i = 0; i < openList.Count; i++)        {                //判断代价F最小的点   或者  F相同判定H较小的点            if (openList[i].fCost < currentNode.fCost ||               (openList[i].fCost == currentNode.fCost && openList[i].hCost < currentNode.hCost))            {                //得出最优点                currentNode = openList[i];            }        }        //移除这个点        openList.Remove(currentNode);        //添加这个节点 不再计算        closeList.Add(currentNode);        //如果得出的最优点为终点 则算出了最终路径 结束        if(currentNode == endNode)        {            //计算路径            GetPath(startNode, endNode);            return;        }        //判断邻居点 哪些符合条件需要添加到待搜索列表中        foreach (Node node in Grid.instance.GetNeighbourNode(currentNode))        {            //不符合条件的节点            if (node.canWalk == false || closeList.Contains(node)) { continue; }            if(!openList.Contains(node))            {                //符合条件的节点需要计算                node.gCost = GetDistance(node, currentNode);                node.hCost = GetDistance(node, endNode);                //设置父节点  方便回溯求路径                node.parent = currentNode;                openList.Add(node);            }        }    }}//计算移动代价或者到达目标点的代价  (采用几何方式计算真实距离)public float GetDistance(Node a,Node b){    return Vector3.Distance(a.position, b.position);}//计算最终路径public void GetPath(Node startNode,Node endNode){    //清除当前路径    path.Clear();    Node temp = endNode;    //开始回溯    while(temp != startNode)    {        path.Add(temp);        temp = temp.parent;    }    //反转 得出 由初始点到终点的路径    path.Reverse();     //传递路径    Grid.instance.path = path;}

}

原创粉丝点击