【A星算法】--第三篇(网格管理器)

这一遍相对复杂,先将代码拆分讲解,在文字最后贴入源码。

首先,在管理器需要用到的参数有

    public int numOfRows;   //行
    public int numOfColums; //列
    public float gridCellSize;  //每一个网格的大小
    public bool showGrid = true;

    private GameObject[] obstacles;//障碍物
    private Node[,] nodes;   //二维数组
    private Vector3 origin = new Vector3(); //原点

讲解一下划线函数OnDrawGizmos()在程序一运行就执行,之后每帧都在执行。根据玩家自定义的行列画出网格样式

    //划线
    void OnDrawGizmos()
    {
        if (showGrid)
        {
            DebugDrawGrid(transform.position, numOfRows, numOfColums, gridCellSize, Color.blue);
        }
        //画一个球体
        Gizmos.DrawSphere(transform.position, 0.5f);

    }

    private void DebugDrawGrid(Vector3 origin, int rows, int colums, float cellSize, Color color)
    {
        float width = colums * cellSize;
        float heigh = rows * cellSize;

        for (int i = 0; i < numOfRows + 1; i++)
        {
            Vector3 starPos = origin + i * cellSize * new Vector3(0.0f, 0.0f, 1.0f);
            Vector3 endPos = starPos + width * new Vector3(1.0f, 0.0f, 0.0f);
            Debug.DrawLine(starPos, endPos, color);
        }

        for (int i = 0; i < numOfColums + 1; i++)
        {
            Vector3 starPos = origin + i * cellSize * new Vector3(1.0f, 0.0f, 0.0f);
            Vector3 endPos = starPos + heigh * new Vector3(0.0f, 0.0f, 1.0f);
            Debug.DrawLine(starPos, endPos, color);
        }
    }

然后再Awake()中寻找该网格的原点(用于搜索网格中的物体),以及网格中的障碍物(本文中障碍物是固定的,如果障碍物是走动之类的,可以将该搜索方法至于update中,或者调用计时器)。在搜索到的障碍物后,用二维数组存放障碍物节点。

    void Awake()
    {
        //搜索原点
        origin = this.transform.position;

        //找到所有的障碍物
        obstacles = GameObject.FindGameObjectsWithTag("Obstacle");
        calculateObstacles();
    }

    private void calculateObstacles()
    {
        nodes = new Node[numOfColums, numOfRows];

        int index = 0;
        //计算所有的网格大小
        for (int i = 0; i < numOfColums; i++)
        {
            for (int j = 0; j < numOfRows; j++)
            {
                Node node = new Node(GetGridCellCenter(index));
                nodes[i, j] = node;
                index++;
            }
        }

        //放入障碍物
        if (obstacles != null && obstacles.Length > 0)
        {
            foreach (GameObject data in obstacles)
            {
                int indexCell = GetGridIndex(data.transform.position);
                int col = GetColumn(indexCell);
                int row = GetRow(indexCell);
                nodes[row, col].MarkAsObstacle();//设置障碍物标记
            }
        }
    }

其中用到的工具方法:


    public int GetGridIndex(Vector3 pos)
    {
        pos -= Origin;
        int col = (int)(pos.x / gridCellSize);
        int row = (int)(pos.z / gridCellSize);

        return (row * numOfColums + col);
    }

    public Vector3 GetGridCellCenter(int index)
    {
        Vector3 cellPostion = GetGridCellPostion(index);
        cellPostion.x += (gridCellSize / 2.0f);
        cellPostion.z += (gridCellSize / 2.0f);
        return cellPostion;
    }

    public Vector3 GetGridCellPostion(int index)
    {
        int row = GetRow(index);
        int col = GetColumn(index);
        float xPosInGrid = col * gridCellSize;
        float zPosInGrid = row * gridCellSize;

        return Origin + new Vector3(xPosInGrid, 0.0f, zPosInGrid);
    }

    public int GetColumn(int index)
    {
        int col = index % numOfColums;
        return col;
    }

    public int GetRow(int index)
    {
        int row = index / numOfColums;
        return row;
    }

这个是一个比较重要的方法,用于获取存入的节点的周围的节点,后面会反复调用

其中1,2,3是距离起点的距离(主要),8是距离终点的距离(大概距离,忽略障碍物不算)

    public void GetNeigighbours(Node node, ArrayList neighbours)
    {
        Vector3 neighborPos = node.postion;
        int neighborIndex = GetGridIndex(neighborPos);

        int row = GetRow(neighborIndex);
        int column = GetColumn(neighborIndex);

        //下
        int nodeRow = row - 1;
        int nodeodeCol = column;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //上
        nodeRow = row + 1;
        nodeodeCol = column;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //右
        nodeRow = row;
        nodeodeCol = column + 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //左
        nodeRow = row;
        nodeodeCol = column - 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //右上
        nodeRow = row + 1;
        nodeodeCol = column + 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //右下
        nodeRow = row - 1;
        nodeodeCol = column + 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //左上
        nodeRow = row + 1;
        nodeodeCol = column - 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //左下
        nodeRow = row - 1;
        nodeodeCol = column - 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);
    }

    private void AssignNeighbour(int row, int col, ArrayList neighbours)
    {
        if (row != -1 && col != -1 && row < numOfRows && col < numOfColums)
        {
            Node nodeToAdd = nodes[row, col];
            if (!nodeToAdd.bObstacle)
            {
                neighbours.Add(nodeToAdd);
            }
        }
    }

以上基本上就是网格管理器的代码。内容简单,希望各位看完后能自己写一个出来,才能深刻。

源码:

/****************************************************
    文件:GridManager.cs
	作者:Jim
    邮箱: 425636780@qq.com
    日期:#CreateTime#
	功能:网格管理器
*****************************************************/

using System;
using System.Collections;
using UnityEngine;

public class GridManager : MonoBehaviour
{
    private static GridManager s_Instance = null;
    public static GridManager instance
    {
        get
        {
            if (s_Instance == null) {
                s_Instance = FindObjectOfType(typeof(GridManager)) as GridManager;
                if (s_Instance == null)
                {
                    Debug.Log("Could not locate an GridManager object.");
                }
            }
            return s_Instance;
        }
    }

    void OnApplicationQuit()
    {
        s_Instance = null;
    }

    public int numOfRows;   //行
    public int numOfColums; //列
    public float gridCellSize;  //每一个网格的大小
    public bool showGrid = true;

    private GameObject[] obstacles;
    private Node[,] nodes;   //二维数组
    private Vector3 origin = new Vector3(); //原点
    public Vector3 Origin
    {
        get { return origin; }
    }

    void Awake()
    {
        //搜索原点
        origin = this.transform.position;

        //找到所有的障碍物
        obstacles = GameObject.FindGameObjectsWithTag("Obstacle");
        calculateObstacles();
    }

    private void calculateObstacles()
    {
        nodes = new Node[numOfColums, numOfRows];

        int index = 0;
        //计算所有的网格大小
        for (int i = 0; i < numOfColums; i++)
        {
            for (int j = 0; j < numOfRows; j++)
            {
                Node node = new Node(GetGridCellCenter(index));
                nodes[i, j] = node;
                index++;
            }
        }

        //放入障碍物
        if (obstacles != null && obstacles.Length > 0)
        {
            foreach (GameObject data in obstacles)
            {
                int indexCell = GetGridIndex(data.transform.position);
                int col = GetColumn(indexCell);
                int row = GetRow(indexCell);
                nodes[row, col].MarkAsObstacle();
            }
        }
    }

    public int GetGridIndex(Vector3 pos)
    {
        pos -= Origin;
        int col = (int)(pos.x / gridCellSize);
        int row = (int)(pos.z / gridCellSize);

        return (row * numOfColums + col);
    }

    public Vector3 GetGridCellCenter(int index)
    {
        Vector3 cellPostion = GetGridCellPostion(index);
        cellPostion.x += (gridCellSize / 2.0f);
        cellPostion.z += (gridCellSize / 2.0f);
        return cellPostion;
    }

    public Vector3 GetGridCellPostion(int index)
    {
        int row = GetRow(index);
        int col = GetColumn(index);
        float xPosInGrid = col * gridCellSize;
        float zPosInGrid = row * gridCellSize;

        return Origin + new Vector3(xPosInGrid, 0.0f, zPosInGrid);
    }

    public int GetColumn(int index)
    {
        int col = index % numOfColums;
        return col;
    }

    public int GetRow(int index)
    {
        int row = index / numOfColums;
        return row;
    }

    //划线
    void OnDrawGizmos()
    {
        if (showGrid)
        {
            DebugDrawGrid(transform.position, numOfRows, numOfColums, gridCellSize, Color.blue);
        }

        Gizmos.DrawSphere(transform.position, 0.5f);

    }

    private void DebugDrawGrid(Vector3 origin, int rows, int colums, float cellSize, Color color)
    {
        float width = colums * cellSize;
        float heigh = rows * cellSize;

        for (int i = 0; i < numOfRows + 1; i++)
        {
            Vector3 starPos = origin + i * cellSize * new Vector3(0.0f, 0.0f, 1.0f);
            Vector3 endPos = starPos + width * new Vector3(1.0f, 0.0f, 0.0f);
            Debug.DrawLine(starPos, endPos, color);
        }

        for (int i = 0; i < numOfColums + 1; i++)
        {
            Vector3 starPos = origin + i * cellSize * new Vector3(1.0f, 0.0f, 0.0f);
            Vector3 endPos = starPos + heigh * new Vector3(0.0f, 0.0f, 1.0f);
            Debug.DrawLine(starPos, endPos, color);
        }
    }

    public void GetNeigighbours(Node node, ArrayList neighbours)
    {
        Vector3 neighborPos = node.postion;
        int neighborIndex = GetGridIndex(neighborPos);

        int row = GetRow(neighborIndex);
        int column = GetColumn(neighborIndex);

        //下
        int nodeRow = row - 1;
        int nodeodeCol = column;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //上
        nodeRow = row + 1;
        nodeodeCol = column;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //右
        nodeRow = row;
        nodeodeCol = column + 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //左
        nodeRow = row;
        nodeodeCol = column - 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        /*
        //右上
        nodeRow = row + 1;
        nodeodeCol = column + 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //右下
        nodeRow = row - 1;
        nodeodeCol = column + 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //左上
        nodeRow = row + 1;
        nodeodeCol = column - 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);

        //左下
        nodeRow = row - 1;
        nodeodeCol = column - 1;
        AssignNeighbour(nodeRow, nodeodeCol, neighbours);
        */
    }

    private void AssignNeighbour(int row, int col, ArrayList neighbours)
    {
        if (row != -1 && col != -1 && row < numOfRows && col < numOfColums)
        {
            Node nodeToAdd = nodes[row, col];
            if (!nodeToAdd.bObstacle)
            {
                neighbours.Add(nodeToAdd);
            }
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值