Park/Paths/PathTilemap.cs
using HC3.Terrain;
using System;
namespace HC3;
/// <summary>
/// A mask representing which directions a path tile connects to.
/// </summary>
[Flags]
public enum PathMask
{
Up = 1 << 1,
Right = 1 << 2,
Down = 1 << 3,
Left = 1 << 4,
All = Up | Right | Down | Left
}
/// <summary>
/// A resource defining the tilemap for path pieces. This isn't really exclusive to paths, it can really be for any tile.
/// </summary>
[AssetType( Name = "Tilemap", Extension = "tilemap" )]
public class PathTileMap : GameResource
{
public class Tileset
{
[Property] public GameObject Single { get; set; }
[Property] public GameObject Straight { get; set; }
[Property] public GameObject Corner { get; set; }
[Property] public GameObject Split { get; set; } // 3 way
[Property] public GameObject Crossing { get; set; } // 4 way
[Property] public GameObject End { get; set; }
[Property] public GameObject Stair { get; set; }
// Todo:
// Building connector
// Support pillars
[Hide]
Dictionary<PathMask, (GameObject, Vector3)> Tiles = new();
public void Init()
{
Tiles.TryAdd( 0, (Single, Vector3.Forward) );
Tiles.TryAdd( PathMask.Up | PathMask.Down, (Straight, Vector3.Left) );
Tiles.TryAdd( PathMask.Left | PathMask.Right, (Straight, Vector3.Forward) );
// Corners
Tiles.TryAdd( PathMask.Down | PathMask.Right, (Corner, Vector3.Forward) );
Tiles.TryAdd( PathMask.Down | PathMask.Left, (Corner, Vector3.Right) );
Tiles.TryAdd( PathMask.Up | PathMask.Right, (Corner, Vector3.Left) );
Tiles.TryAdd( PathMask.Up | PathMask.Left, (Corner, Vector3.Backward) );
// End caps
Tiles.TryAdd( PathMask.Left, (End, Vector3.Backward) );
Tiles.TryAdd( PathMask.Right, (End, Vector3.Forward) );
Tiles.TryAdd( PathMask.Up, (End, Vector3.Left) );
Tiles.TryAdd( PathMask.Down, (End, Vector3.Right) );
// 3 splits
Tiles.TryAdd( PathMask.Up | PathMask.Left | PathMask.Right, (Split, Vector3.Backward) );
Tiles.TryAdd( PathMask.Down | PathMask.Left | PathMask.Right, (Split, Vector3.Forward) );
Tiles.TryAdd( PathMask.Up | PathMask.Down | PathMask.Left, (Split, Vector3.Right) );
Tiles.TryAdd( PathMask.Up | PathMask.Down | PathMask.Right, (Split, Vector3.Left) );
// 4 split
Tiles.TryAdd( PathMask.Up | PathMask.Left | PathMask.Right | PathMask.Down, (Crossing, Vector3.Forward) );
}
public (GameObject, Vector3) GetTile( PathMask mask, Vector2Int stairDirection )
{
if ( stairDirection == 0 || !Stair.IsValid() )
{
if ( Tiles.TryGetValue( mask, out var t ) )
return t;
Log.Info( $"Couldn't find path for {mask} ({(int)mask})" );
return (Single, Vector3.Forward);
}
return (Stair, (Vector2)stairDirection);
}
}
[Property] public Tileset Default { get; set; }
[Property] public Tileset Elevated { get; set; }
protected override void PostLoad()
{
Default.Init();
Elevated.Init();
}
public (GameObject, Vector3) GetTile( PathMask mask, Vector2Int stairDirection, bool elevated )
{
var tileset = elevated ? Elevated : Default;
return (tileset ?? Default).GetTile( mask, stairDirection );
}
}
public static class PathMaskExtensions
{
public static PathMask Rotate90DegreesClockwise( this PathMask mask )
{
return (PathMask)(((int)mask << 1) | ((int)mask >> 3)) & PathMask.All;
}
public static bool CanConnectTile( this PathMask mask, TileEdge edge )
{
return (mask & edge.ToPathMask()) != 0;
}
public static IEnumerable<TileEdge> GetEdges( this PathMask mask ) =>
GridManager.AllEdges.Where( x => mask.CanConnectTile( x ) );
public static int GetCount( this PathMask mask )
{
var count = 0;
foreach ( var edge in GridManager.AllEdges )
{
if ( mask.CanConnectTile( edge ) )
{
++count;
}
}
return count;
}
}