手撸一个A*+二叉堆优化(三)

添加了player之后就需要得到player真实坐标对应的网格,所以需要一个根据世界坐标返回数组内坐标的方法

 public Node GetFromPositon(Vector3 positon)
    {
        float percentX = (positon.x + gridSize.x / 2) / gridSize.x;
        float percentY = (positon.z+ gridSize.y / 2) / gridSize.y;
        percentX = Mathf.Clamp01(percentX);
        percentY = Mathf.Clamp01(percentY);

        int x = Mathf.RoundToInt((gridCntX - 1) * percentX);
        int y = Mathf.RoundToInt((gridCntY - 1) * percentY);

        return grid[x, y];
    }

FindPath类中开始搜索

public Transform player;
    public Transform target;
    private Grid _gird;

得到初始点和目标点以及我们创造的Grid

先写一个计算估值的方法

private int GetDistanceNodes(Node a, Node b)
    {
        int cntX = Mathf.Abs(a._gridX - b._gridX);
        int cntY = Mathf.Abs(a._gridY - b._gridY);
        if (cntX>cntY)
        {
            // return 10 * cntY + 10 * (cntX - cntY);
            return 14 * cntY + 10 * (cntX - cntY);
        }
        else
        {
            //  return 10* cntX + 10 * (cntY - cntX);
            return 14 * cntX + 10 * (cntY - cntX);
        }
    }

X大于Y就先向上走斜角再走水平直线,X小于Y就先向旁边就斜角再走垂直直线。

再写搜索的方法

void FindingPath(Vector3 StartPos,Vector3 EndPos)
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();

        Node startNode = _gird.GetFromPositon(StartPos);
        Node endNode = _gird.GetFromPositon(EndPos);
        List openSet = new List();
        HashSet closeSet = new HashSet();
        openSet.Add(startNode);//加入开启列表
//遍历开启列表
        while (openSet.Count()>0)
        {
            Node CurrentNode = openSet[0];

            for (int i = 0; i < openSet.Count; i++)
            {
                if (openSet[i].fCost

至于关闭列表为什么要用HashSet,那肯定是为了提高查找效率,HashSet不包含重复元素,并且其中存储的元素没有特定的顺序,插入元素的操作非常快,不需要像List类那样重排集合。

再写一个生成路径点的方法,也就是找父节点,依次加入path集合

private void GeneratePaht(Node startNode,Node endNode)
    {
        List path = new List();
        Node temp = endNode;
        while (temp!=startNode)
        {
            path.Add(temp);
            temp = temp.parent;
        }
        path.Reverse();//反转
        _gird.path = path;
    }

接着回到Grid,写寻找周围格子的方法

 public List GetNerbourhood(Node node)
    {
        List neibourhood = new List();

        for (int i = -1; i <= 1; i++)
        {
            for (int j = -1; j <= 1; j++)
            {
                //  if ((i == 0 && j == 0)||(i==-1&&(j==1||j==-1)||(i==1&&(j==1||j==-1)))) continue;
                if ((i == 0 && j == 0)) continue;
                int tempX = node._gridX + i;
                int tempY = node._gridY + j;
//不能超出格子范围
                if (tempX < gridCntX && tempX > 0 && tempY > 0 && tempY < gridCntY)
                {
                    neibourhood.Add(grid[tempX,tempY]);
                }
            }
        }
        return neibourhood;
    }

现在只要在FindPath的update里执行搜索就可以了

    void Update()
    {
        //if(Input.GetKeyDown(KeyCode.J))
        FindingPath(player.position,target.position);
    }

同样可以用OnDrawGizmos显示我们计算出来的路径点

 if (path != null)
{
                foreach (var node in path)
                {
                    Gizmos.color = Color.black;
                    Gizmos.DrawCube(node._worldPos, Vector3.one * (nodeDiameter - .1f));
                }
 }

在搜索的方法里写了Stopwatch,可以在console里看到消耗的时间,如果不明显,可以增加地图的大小,我的plane大小是10,格子半径1,也就是地图是50X50.


在下一篇里将会用二叉堆对搜索方法进行优化,主要是优化开启列表的遍历搜索

你可能感兴趣的:(unity)