1. 程式人生 > >小妖精的完美遊戲教室——人工智能,A*算法,導航網絡篇

小妖精的完美遊戲教室——人工智能,A*算法,導航網絡篇

mono bool rom layer eric art toml -1 ble

//================================================================
//
// Copyright (C) 2017 Team Saluka
// All Rights Reserved
//
// Author:小妖精Balous
//
//================================================================

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Saruka
{
/// <summary>
/// 導航網格
/// </summary>
public class NavGrid : MonoBehaviour
{
/// <summary>
/// 景物層級,用來建立導航網格
/// </summary>
public LayerMask scapeMask;
/// <summary>
/// 導航網格大小
/// </summary>
public Vector2 navGridSize;
/// <summary>
/// 單個網格半徑
/// </summary>
public float gridRadius;
/// <summary>
/// 單個網格直徑
/// </summary>
float gridDiameter;
/// <summary>
/// 網格結點
/// </summary>
public NavNode[,] grids
{
private set;
get;
}
/// <summary>
/// X軸方向網格數量
/// </summary>
public int gridCountX
{
private set;
get;
}
/// <summary>
/// Y軸方向網格數量
/// </summary>
public int gridCountY
{
private set;
get;
}

/// <summary>
/// 創建導航網格
/// </summary>
void CreateNavGrid()
{
gridDiameter = gridRadius * 2;
gridCountX = Mathf.RoundToInt(navGridSize.x / gridDiameter);
gridCountY = Mathf.RoundToInt(navGridSize.y / gridDiameter);

grids = new NavNode[gridCountX, gridCountY];

//導航網格左下角,平面直角坐標系
Vector3 navGridBottomLeft = transform.position - Vector3.right * navGridSize.x / 2 - Vector3.up * navGridSize.y / 2;

//創建網格
for (int x = 0; x < gridCountX; x++)
for (int y = 0; y < gridCountY; y++)
{
//網格中心坐標
Vector3 gridCenter = navGridBottomLeft + Vector3.right * (x * gridDiameter + gridRadius) + Vector3.up * (y * gridDiameter + gridRadius);
bool isWalkable = !(Physics2D.CircleCast(new Vector2(gridCenter.x, gridCenter.y), gridRadius, Vector2.zero, 0.0f, scapeMask));
grids[x, y] = new NavNode(gridCenter, isWalkable, x, y);
}
}

/// <summary>
/// 獲得世界坐標所在的結點
/// </summary>
/// <param name="worldPosition">世界坐標</param>
/// <returns>結點</returns>
public NavNode NavNodeFromWorldPosition(Vector3 worldPosition)
{
worldPosition -= transform.position;
float percentX = Mathf.Clamp01((worldPosition.x + navGridSize.x / 2) / navGridSize.x);
float percentY = Mathf.Clamp01((worldPosition.y + navGridSize.y / 2) / navGridSize.y);
int x = Mathf.RoundToInt((gridCountX - 1) * percentX);
int y = Mathf.RoundToInt((gridCountY - 1) * percentY);
return grids[x, y];
}

public List<NavNode> GetNeighborNodes(NavNode navNode)
{
List<NavNode> neighborNodes = new List<NavNode>();

for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0) continue;

int checkX = navNode.gridX + x;
int checkY = navNode.gridY + y;
if (checkX >= 0 && checkX < gridCountX && checkY >= 0 && checkY < gridCountY) neighborNodes.Add(grids[checkX, checkY]);
}
}
return neighborNodes;
}

void OnDrawGizmos()
{
//導航網格邊框
Gizmos.DrawWireCube(transform.position, new Vector3(navGridSize.x, navGridSize.y, 1));

if(grids != null)
{
foreach(NavNode node in grids)
{
Gizmos.color = (node.isWalkable) ? new Color(1, 1, 1, 0.4f) : new Color(1, 0, 0, 0.4f);
Gizmos.DrawCube(node.worldPosition, Vector3.one * (gridDiameter - 0.03f));
}
}
}

// Use this for initialization
void Start()
{
CreateNavGrid();
}
}
}

小妖精的完美遊戲教室——人工智能,A*算法,導航網絡篇