unity astar生成栅格代码
时间: 2023-09-30 08:05:05 浏览: 116
FairyGUI & Unity 代码自动生成,附带自定义编辑包
以下是一个简单的Unity A*算法生成栅格代码示例:
```csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GridGenerator : MonoBehaviour
{
public LayerMask unwalkableMask; // 不可行走区域的层级
public Vector2 gridWorldSize; // 栅格世界大小
public float nodeRadius; // 节点半径
public TerrainType[] walkableRegions; // 可行走区域列表
public int obstacleProximityPenalty = 10; // 障碍物距离惩罚
public bool displayGridGizmos; // 是否显示栅格边框
Node[,] grid; // 二维栅格数组
float nodeDiameter;
int gridSizeX, gridSizeY;
int penaltyMin = int.MaxValue;
int penaltyMax = int.MinValue;
Dictionary<int, int> walkableRegionsDictionary = new Dictionary<int, int>();
void Awake()
{
nodeDiameter = nodeRadius * 2;
gridSizeX = Mathf.RoundToInt(gridWorldSize.x / nodeDiameter);
gridSizeY = Mathf.RoundToInt(gridWorldSize.y / nodeDiameter);
foreach (TerrainType region in walkableRegions)
{
unwalkableMask |= region.terrainMask;
walkableRegionsDictionary.Add((int)Mathf.Log(region.terrainMask.value, 2), region.terrainPenalty);
}
CreateGrid();
}
public int MaxSize { get { return gridSizeX * gridSizeY; } }
void CreateGrid()
{
grid = new Node[gridSizeX, gridSizeY];
Vector3 worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x / 2 - Vector3.forward * gridWorldSize.y / 2;
for (int x = 0; x < gridSizeX; x++)
{
for (int y = 0; y < gridSizeY; y++)
{
Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (y * nodeDiameter + nodeRadius);
bool walkable = !(Physics.CheckSphere(worldPoint, nodeRadius, unwalkableMask));
int movementPenalty = 0;
if (walkable)
{
Ray ray = new Ray(worldPoint + Vector3.up * 50, Vector3.down);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100, unwalkableMask))
{
walkableRegionsDictionary.TryGetValue(hit.collider.gameObject.layer, out movementPenalty);
}
}
if (!walkable)
{
movementPenalty += obstacleProximityPenalty;
}
grid[x, y] = new Node(walkable, worldPoint, x, y, movementPenalty);
}
}
BlurPenaltyMap(3);
}
void BlurPenaltyMap(int blurSize)
{
int kernelSize = blurSize * 2 + 1;
int[,] penaltiesHorizontalPass = new int[gridSizeX, gridSizeY];
int[,] penaltiesVerticalPass = new int[gridSizeX, gridSizeY];
for (int y = 0; y < gridSizeY; y++)
{
for (int x = -blurSize; x <= blurSize; x++)
{
int sampleX = Mathf.Clamp(x, 0, blurSize);
penaltiesHorizontalPass[0, y] += grid[sampleX, y].movementPenalty;
}
for (int x = 1; x < gridSizeX; x++)
{
int removeIndex = Mathf.Clamp(x - blurSize - 1, 0, gridSizeX);
int addIndex = Mathf.Clamp(x + blurSize, 0, gridSizeX - 1);
penaltiesHorizontalPass[x, y] = penaltiesHorizontalPass[x - 1, y]
- grid[removeIndex, y].movementPenalty
+ grid[addIndex, y].movementPenalty;
}
}
for (int x = 0; x < gridSizeX; x++)
{
for (int y = -blurSize; y <= blurSize; y++)
{
int sampleY = Mathf.Clamp(y, 0, blurSize);
penaltiesVerticalPass[x, 0] += penaltiesHorizontalPass[x, sampleY];
}
int blurredPenalty = Mathf.RoundToInt((float)penaltiesVerticalPass[x, 0] / (kernelSize * kernelSize));
grid[x, 0].movementPenalty = blurredPenalty;
penaltyMin = Mathf.Min(penaltyMin, blurredPenalty);
penaltyMax = Mathf.Max(penaltyMax, blurredPenalty);
for (int y = 1; y < gridSizeY; y++)
{
int removeIndex = Mathf.Clamp(y - blurSize - 1, 0, gridSizeY);
int addIndex = Mathf.Clamp(y + blurSize, 0, gridSizeY - 1);
penaltiesVerticalPass[x, y] = penaltiesVerticalPass[x, y - 1]
- penaltiesHorizontalPass[x, removeIndex]
+ penaltiesHorizontalPass[x, addIndex];
blurredPenalty = Mathf.RoundToInt((float)penaltiesVerticalPass[x, y] / (kernelSize * kernelSize));
grid[x, y].movementPenalty = blurredPenalty;
penaltyMin = Mathf.Min(penaltyMin, blurredPenalty);
penaltyMax = Mathf.Max(penaltyMax, blurredPenalty);
}
}
}
public List<Node> GetNeighbours(Node node)
{
List<Node> neighbours = new List<Node>();
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0)
continue;
int checkX = node.gridX + x;
int checkY = node.gridY + y;
if (checkX >= 0 && checkX < gridSizeX && checkY >= 0 && checkY < gridSizeY)
{
neighbours.Add(grid[checkX, checkY]);
}
}
}
return neighbours;
}
public Node NodeFromWorldPoint(Vector3 worldPosition)
{
float percentX = (worldPosition.x + gridWorldSize.x / 2) / gridWorldSize.x;
float percentY = (worldPosition.z + gridWorldSize.y / 2) / gridWorldSize.y;
percentX = Mathf.Clamp01(percentX);
percentY = Mathf.Clamp01(percentY);
int x = Mathf.RoundToInt((gridSizeX - 1) * percentX);
int y = Mathf.RoundToInt((gridSizeY - 1) * percentY);
return grid[x, y];
}
void OnDrawGizmos()
{
Gizmos.DrawWireCube(transform.position, new Vector3(gridWorldSize.x, 1, gridWorldSize.y));
if (grid != null && displayGridGizmos)
{
foreach (Node n in grid)
{
Gizmos.color = Color.Lerp(Color.white, Color.black, Mathf.InverseLerp(penaltyMin, penaltyMax, n.movementPenalty));
Gizmos.color = (n.walkable) ? Gizmos.color : Color.red;
Gizmos.DrawCube(n.worldPosition, Vector3.one * (nodeDiameter - .1f));
}
}
}
[System.Serializable]
public class TerrainType
{
public LayerMask terrainMask;
public int terrainPenalty;
}
}
```
在这个示例中,我们首先定义了一些变量,包括不可行走区域的层级、栅格世界大小、节点半径、可行走区域列表、障碍物距离惩罚和是否显示栅格边框等。然后在Awake()函数中,我们初始化了一些变量,包括根据节点半径计算出的节点直径、栅格大小、可行走区域列表等,并调用CreateGrid()函数生成栅格。
在CreateGrid()函数中,我们首先创建一个二维栅格数组,然后根据栅格世界大小和节点直径计算出左下角的世界坐标,接着遍历二维数组,为每个节点生成一个世界坐标。接下来,我们使用CheckSphere()函数检查该节点是否在不可行走区域中,如果是,则设置walkable变量为false,并增加障碍物距离惩罚,否则设置walkable变量为true。然后我们使用Raycast()函数检查节点下方是否有可行走区域,如果有,我们使用walkableRegionsDictionary查找该区域的movementPenalty,否则movementPenalty为0。最后,我们为每个节点创建一个Node对象,并将其添加到二维栅格数组中。
接下来,我们调用BlurPenaltyMap()函数对栅格中的障碍物距离惩罚进行模糊处理。该函数使用一个二维数组penaltiesHorizontalPass和一个二维数组penaltiesVerticalPass来存储水平和垂直方向上的惩罚值,并使用一个kernelSize计算出每个节点的平均惩罚值。最后,我们使用NodeFromWorldPoint()函数将世界坐标转换为节点,并使用Gizmos.DrawCube()函数在Unity编辑器中显示栅格边框。
这是一个非常简单的Unity A*算法生成栅格代码示例,它可以让你快速了解如何使用A*算法生成栅格。如果你想了解更多关于Unity A*算法的知识,请参考Unity官方文档。
阅读全文