NLDClient-yudde/ProjectNLD/Assets/ThirdParty/TerrainGridSystem/Scripts/TGS_NLDExtents.cs

367 lines
16 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using TGS.PathFinding;
using UnityEngine;
namespace TGS
{
public partial class Cell
{
public int crossLevel = 0;
public bool isVisited = false;
public bool isInArea = false;
public Vector3Int mathPointV3;
public bool CanCross(int crossLevel)
{
return crossLevel > this.crossLevel && canCross;
}
public void ForceCanCross(bool value)
{
canCross = value;
crossLevel = value ? 0 : Int32.MaxValue;
}
}
public partial class TerrainGridSystem
{
public int CellGetCrossLevel(int cellIndex)
{
if (!ValidCellIndex(cellIndex)) return 0;
return cells[cellIndex].crossLevel;
}
public void CellSetCrossLevel(int cellIndex, int crossLevel)
{
if (!ValidCellIndex(cellIndex)) return;
cells[cellIndex].crossLevel = crossLevel;
needRefreshRouteMatrix = true;
}
public void CellSetCrossLevel(List<int> cellIndices, int crossLevel)
{
int count = cellIndices.Count;
for (int k = 0; k < count; k++)
{
Cell cell = cells[cellIndices[k]];
cell.crossLevel = crossLevel;
}
needRefreshRouteMatrix = true;
}
public List<int> FindPath(int cellIndexStart, int cellIndexEnd, int crossLevel, float maxSearchCost = 0, int maxSteps = 0, int cellGroupMask = -1, CanCrossCheckType canCrossCheckType = CanCrossCheckType.Default, bool ignoreCellCosts = false, bool includeInvisibleCells = true, int minClearance = 1, float maxCellCrossCost = float.MaxValue) {
float dummy;
return FindPath(cellIndexStart, cellIndexEnd, crossLevel, out dummy, maxSearchCost, maxSteps, cellGroupMask, canCrossCheckType, ignoreCellCosts, includeInvisibleCells, minClearance, maxCellCrossCost);
}
public List<int> FindPath(int cellIndexStart, int cellIndexEnd, int crossLevel, out float totalCost, float maxSearchCost = 0, int maxSteps = 0, int cellGroupMask = -1, CanCrossCheckType canCrossCheckType = CanCrossCheckType.Default, bool ignoreCellCosts = false, bool includeInvisibleCells = true, int minClearance = 1, float maxCellCrossCost = float.MaxValue) {
List<int> results = new List<int>();
FindPath(cellIndexStart, cellIndexEnd, results, crossLevel,out totalCost, maxSearchCost, maxSteps, cellGroupMask, canCrossCheckType, ignoreCellCosts, includeInvisibleCells, minClearance, maxCellCrossCost);
return results;
}
public void FindPath(List<int> result,
int cellIndexStart,
int cellIndexEnd,
int crossLevel)
{
FindPath(cellIndexStart, cellIndexEnd, result, crossLevel, out _);
}
public int FindPath(int cellIndexStart, int cellIndexEnd, List<int> cellIndices, int crossLevel, out float totalCost, float maxSearchCost = 0, int maxSteps = 0, int cellGroupMask = -1, CanCrossCheckType canCrossCheckType = CanCrossCheckType.Default, bool ignoreCellCosts = false, bool includeInvisibleCells = true, int minClearance = 1, float maxCellCrossCost = float.MaxValue) {
totalCost = 0;
if (cellIndices == null) return 0;
cellIndices.Clear();
if (cellIndexStart == cellIndexEnd || cellIndexStart < 0 || cellIndexEnd < 0 || cellIndexStart >= cells.Count || cellIndexEnd >= cells.Count) return 0;
Cell startCell = cells[cellIndexStart];
Cell endCell = cells[cellIndexEnd];
if (startCell == null || endCell == null) return 0;
bool startCellCanCross = startCell.canCross;
bool endCellCanCross = endCell.canCross;
int startCellCrossLevel = startCell.crossLevel;
int endCellCrossLevel = endCell.crossLevel;
if (canCrossCheckType != CanCrossCheckType.IgnoreCanCrossCheckOnAllCells) {
switch (canCrossCheckType) {
case CanCrossCheckType.ignoreCanCrossCheckOnStartAndEndCells:
startCell.ForceCanCross(true);
endCell.ForceCanCross(true);
break;
case CanCrossCheckType.ignoreCanCrossCheckOnStartCells:
if (!endCell.CanCross(crossLevel)) return 0;
startCell.ForceCanCross(true);
break;
case CanCrossCheckType.ignoreCanCrossCheckOnEndCells:
if (!startCell.CanCross(crossLevel)) return 0;
endCell.ForceCanCross(true);
break;
default:
if (!startCell.CanCross(crossLevel) || !endCell.CanCross(crossLevel))
return 0;
break;
}
}
if (needRefreshRouteMatrix && minClearance > 1) {
ComputeClearance(cellGroupMask, crossLevel);
}
ComputeRouteMatrix();
finder.Formula = _pathFindingHeuristicFormula;
finder.MaxSteps = maxSteps > 0 ? maxSteps : _pathFindingMaxSteps;
finder.Diagonals = _pathFindingUseDiagonals;
finder.HeavyDiagonalsCost = _pathFindingHeavyDiagonalsCost;
switch(_gridTopology)
{
case GridTopology.Irregular: finder.CellShape = CellType.Irregular; break;
case GridTopology.Hexagonal: finder.CellShape = _pointyTopHexagons ? CellType.PointyTopHexagon : CellType.FlatTopHexagon; break;
default: finder.CellShape = CellType.Box; break;
}
finder.MaxSearchCost = maxSearchCost > 0 ? maxSearchCost : _pathFindingMaxCost;
finder.CellGroupMask = cellGroupMask;
finder.IgnoreCanCrossCheck = canCrossCheckType == CanCrossCheckType.IgnoreCanCrossCheckOnAllCells || canCrossCheckType == CanCrossCheckType.ignoreCanCrossCheckOnAllCellsExceptStartAndEndCells;
finder.IgnoreCellCost = ignoreCellCosts;
finder.IncludeInvisibleCells = includeInvisibleCells;
finder.MinClearance = minClearance;
finder.MaxCellCrossCost = maxCellCrossCost;
if (OnPathFindingCrossCell != null) {
finder.OnCellCross = FindRoutePositionValidator;
} else {
finder.OnCellCross = null;
}
List<PathFinderNode> route = finder.FindPath(this, startCell, endCell,crossLevel, out totalCost, _evenLayout);
startCell.canCross = startCellCanCross;
endCell.canCross = endCellCanCross;
startCell.crossLevel = startCellCrossLevel;
endCell.crossLevel = endCellCrossLevel;
if (route != null) {
int routeCount = route.Count;
if (_gridTopology == GridTopology.Irregular) {
for (int r = routeCount - 2; r >= 0; r--) {
cellIndices.Add(route[r].PX);
}
} else {
for (int r = routeCount - 2; r >= 0; r--) {
int cellIndex = route[r].PY * _cellColumnCount + route[r].PX;
cellIndices.Add(cellIndex);
}
}
cellIndices.Add(cellIndexEnd);
} else {
return 0; // no route available
}
return cellIndices.Count;
}
/// <summary>
/// Updates clearance data for each cell. Clearance is used with FindPath method (minClearance parameter) and it's used to specify the minimum width of a path
/// </summary>
public void ComputeClearance(int cellGroupMask, int objectCrossLevel) {
if (clearanceComputed && clearanceCellGroupMask == cellGroupMask) return;
clearanceComputed = true;
clearanceCellGroupMask = cellGroupMask;
int cellsCount = cells.Count;
// clear clearance
for (int k = 0; k < cellsCount; k++) {
cells[k].clearance = 0;
}
int maxDim = Mathf.Max(rowCount, columnCount);
// uses true clearance
for (int j = rowCount - 1; j >= 0; j--) {
for (int k = 0; k < columnCount; k++) {
Cell cell = CellGetAtPosition(k, j);
if (cell == null) continue;
for (int maxClearance = 2; maxClearance < maxDim; maxClearance++) {
bool blocked = false;
int maxIter = maxClearance * maxClearance;
for (int i = 1; i < maxIter; i++) {
int nj = j - (i / maxClearance);
int nk = k + (i % maxClearance);
if (nj < 0 || nk >= columnCount) {
blocked = true;
break;
}
Cell neighbour = CellGetAtPosition(nk, nj);
if (neighbour == null || (neighbour.group & cellGroupMask) == 0 || !neighbour.CanCross(objectCrossLevel)) {
blocked = true;
break;
}
}
if (blocked) {
cell.clearance = (byte)(maxClearance - 1);
break;
}
}
}
}
}
public bool CellGetLineOfSight(int startCellIndex, int endCellIndex, int crossLevel, ref List<int> cellIndices, ref List<Vector3> worldPositions, int cellGroupMask = -1, int lineResolution = 2, bool exhaustiveCheck = false, bool ignoreCanCrossCheck = false, bool checkLastCell = false)
{
if (cellIndices == null)
{
cellIndices = new List<int>();
}
else
{
cellIndices.Clear();
}
if (worldPositions == null)
{
worldPositions = new List<Vector3>();
}
else
{
worldPositions.Clear();
}
if (startCellIndex < 0 || startCellIndex >= cells.Count || endCellIndex < 0 || endCellIndex >= cells.Count)
return false;
Vector3 startPosition = CellGetPosition(startCellIndex);
Vector3 endPosition;
int vertexCount = exhaustiveCheck ? cells[endCellIndex].region.points.Count : 0;
bool success = true;
for (int p = 0; p <= vertexCount; p++)
{
if (p == 0)
{
endPosition = CellGetPosition(endCellIndex);
}
else
{
cellIndices.Clear();
worldPositions.Clear();
endPosition = CellGetVertexPosition(endCellIndex, p - 1);
}
int numSteps;
switch (_gridTopology)
{
case GridTopology.Hexagonal:
// Hexagon distance
numSteps = CellGetHexagonDistance(startCellIndex, endCellIndex);
lineResolution = Mathf.Max(2, lineResolution);
numSteps *= lineResolution;
break;
case GridTopology.Box:
numSteps = CellGetBoxDistance(startCellIndex, endCellIndex);
lineResolution = Mathf.Max(2, lineResolution);
numSteps *= lineResolution;
if (numSteps % 2 == 0)
numSteps++;
break;
default:
float dist = Vector3.Distance(startPosition, endPosition);
numSteps = Mathf.CeilToInt(dist * lineResolution);
break;
}
Cell lastCell = cells[startCellIndex];
success = true;
for (int k = 1; k <= numSteps; k++)
{
Vector3 position = Vector3.Lerp(startPosition, endPosition, (float)k / numSteps);
Cell cell = k == numSteps ? cells[endCellIndex] : CellGetAtPosition(position, true);
if (cell != null && cell != lastCell)
{
if (checkLastCell || cell != cells[endCellIndex])
{
if (!cell.CanCross(crossLevel) && !ignoreCanCrossCheck)
{
success = false;
break;
}
if ((cell.group & cellGroupMask) == 0)
{
success = false;
break;
}
}
// Check LOD blocks
if (LOSIsBlocked(lastCell, cell) || LOSIsBlocked(cell, lastCell))
{
success = false;
break;
}
cellIndices.Add(cell.index);
lastCell = cell;
}
worldPositions.Add(position);
}
if (success)
{
if (p == 0 && _gridTopology != GridTopology.Irregular)
{
return true;
}
break;
}
}
if (success)
{
CellGetLine(startCellIndex, endCellIndex, ref cellIndices, ref worldPositions, lineResolution);
}
return success;
}
public bool CellGetLineOfSight(Vector3 startPosition, Vector3 endPosition, int crossLevel, ref List<int> cellIndices, ref List<Vector3> worldPositions, int cellGroupMask = -1, int lineResolution = 2, bool exhaustiveCheck = false, bool ignoreCanCrossCheck = false, bool checkLastCell = false)
{
cellIndices = null;
Cell startCell = CellGetAtPosition(startPosition, true);
Cell endCell = CellGetAtPosition(endPosition, true);
if (startCell == null || endCell == null)
{
return false;
}
int cell1 = CellGetIndex(startCell);
int cell2 = CellGetIndex(endCell);
if (cell1 < 0 || cell2 < 0)
return false;
return CellGetLineOfSight(cell1, cell2, crossLevel, ref cellIndices, ref worldPositions, cellGroupMask, lineResolution, exhaustiveCheck, ignoreCanCrossCheck, checkLastCell);
}
public void CellTestLineOfSight(int startCellIndex, List<int> targetCellIndices, int crossLevel, int cellGroupMask = -1, int lineResolution = 2, bool exhaustiveCheck = false, bool ignoreCanCrossCheck = false, bool checkLastCell = false)
{
int count = targetCellIndices.Count;
List<Vector3> dummyPositions = null;
cellIteration++;
for (int k = 0; k < count; k++)
{
int targetCellIndex = targetCellIndices[k];
if (cells[targetCellIndex].iteration != cellIteration)
{
if (CellGetLineOfSight(startCellIndex, targetCellIndex, crossLevel, ref tempListCells, ref dummyPositions, cellGroupMask, lineResolution, exhaustiveCheck, ignoreCanCrossCheck, checkLastCell))
{
int lineCount = tempListCells.Count;
for (int j = 0; j < lineCount; j++)
{
int index = tempListCells[j];
cells[index].iteration = cellIteration;
}
}
else
{
targetCellIndices.RemoveAt(k);
k--;
count--;
}
}
}
}
}
}