Park/GridManager.Regions.cs
using HC3.Terrain;
namespace HC3;
public partial class GridManager : ITerrainEvent
{
[Property, Hide] public Vector3Int EntranceGridPos { get; private set; }
[Rpc.Broadcast]
void BroadcastEntranceMoved( Vector3Int gridPos )
{
EntranceGridPos = gridPos;
}
void ITerrainEvent.EntranceMoved( Vector3Int gridPos )
{
BroadcastEntranceMoved( gridPos );
}
public IEnumerable<GridObject> Walkable => _walkableObjects;
/// <summary>
/// Assigns every known cell with a region Id.
/// Every disconnected island forms a new region id, with the entrance at 0.
/// </summary>
public void DirtyRegions()
{
// TODO: run this on a background thread?
var pos2d = new Vector2Int( EntranceGridPos );
if ( !_cells.TryGetValue( pos2d, out GridCell startCell ) )
{
return;
}
Path startPath = startCell.GetComponents<Path>( EntranceGridPos.z ).FirstOrDefault();
if ( !startPath.IsValid() )
{
return;
}
foreach ( var gridObject in _walkableObjects )
gridObject.RegionId = -1;
int nextRegionId = 0;
if ( startCell != null )
AssignRegionsFrom( startPath.GridObject, ref nextRegionId );
foreach ( var cell in Walkable.Where( x => x.RegionId == -1 ) )
{
AssignRegionsFrom( cell, ref nextRegionId );
}
}
private void AssignRegionsFrom( GridObject current, ref int nextRegionId )
{
var queue = new Queue<GridObject>();
queue.Enqueue( current );
current.RegionId = nextRegionId;
while ( queue.Count > 0 )
{
var cell = queue.Dequeue();
Vector3Int cellPos = WorldToGridPosition3D( cell.WorldPosition );
foreach ( var neighbor in GridNavigation.Instance.GetEnterableNeighbors( cellPos, NavFlags.None )
.SelectMany( x => Instance.GetCell( new Vector2Int( x ) ).GetComponents<GridObject>( x.z ) )
.Where( x => x.RegionId == -1 ) )
{
neighbor.RegionId = nextRegionId;
queue.Enqueue( neighbor );
}
}
nextRegionId++;
}
public static int GetRegion( Vector3Int pos )
{
var pos2d = new Vector2Int( pos.x, pos.y );
if ( Instance.GetCell( pos2d ) is not { } cell )
{
return -1;
}
var path = cell.GetComponents<GridObject>( pos.z ).FirstOrDefault();
return path.IsValid() ? path.RegionId : -1;
}
public static bool IsWalkable( Vector3 worldStart, Vector3 worldTarget )
{
var startGrid = WorldToGridPosition3D( worldStart );
var targetGrid = WorldToGridPosition3D( worldTarget );
return IsWalkable( startGrid, targetGrid );
}
public static bool IsWalkable( Vector3Int startGrid, Vector3Int targetGrid )
{
var start2d = new Vector2Int( startGrid.x, startGrid.y );
if ( Instance.GetCell( start2d ) is not { } startCell )
{
return false;
}
var target2d = new Vector2Int( targetGrid.x, targetGrid.y );
if ( Instance.GetCell( target2d ) is not { } goalCell )
{
return false;
}
var startPath = startCell.GetComponents<GridObject>( startGrid.z ).FirstOrDefault();
var targetPath = goalCell.GetComponents<GridObject>( targetGrid.z ).FirstOrDefault();
if ( !startPath.IsValid() || !targetPath.IsValid() )
{
return false;
}
return startPath.RegionId == targetPath.RegionId && startPath.RegionId != -1;
}
}