这一遍相对复杂,先将代码拆分讲解,在文字最后贴入源码。
首先,在管理器需要用到的参数有
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);
}
}
}
}