Grid System
Wayfinder’s grid system handles tile management, pathfinding, range calculation, and height-based mechanics for isometric tactical combat.
Core Components
Tile
Represents a single grid tile in the battle map.
public class Tile : MonoBehaviour
{
public Vector3Int gridLocation; // 3D grid position (x, y, z)
public Vector2Int grid2DLocation; // 2D position (x, y)
public float height; // Visual height of tile
public UnitStateManager currentUnit; // Unit occupying this tile
public TileStatus status; // Passable, Blocked, InAbilityRange, InAoEPattern
}Key Properties:
gridLocation- Full 3D position including height (Z-axis)grid2DLocation- 2D position for pathfinding (X, Y only)height- Visual height for renderingcurrentUnit- Which unit is on this tile (null if empty)
TileManager
Manages the grid tilemap and provides tile lookup/neighbor finding.
public class TileManager : MonoBehaviour
{
public Dictionary<Vector2Int, Tile> map; // All tiles by 2D position
public Tile GetAdjacentTile(Tile currentTile, int xDiff, int yDiff);
public List<Tile> GetNeighborTiles(Tile currentTile, Unit unit,
List<Tile> searchableTiles, bool ignoreHeight);
public Tile GetUnitCurrentTile(UnitStateManager unit);
}Methods:
GetNeighborTiles- Returns valid adjacent tiles for pathfindingGetAdjacentTile- Gets tile at offset positionGetUnitCurrentTile- Finds which tile a unit is on
Pathfinding
Pathfinder Class
A* pathfinding with tactical RPG movement rules.
public class Pathfinder
{
public List<Tile> FindPath(TileManager tileManager, Unit unit,
Tile start, Tile end, List<Tile> searchableTiles,
bool ignoreHeight, int minRange = 0);
public int GetPathDistance(TileManager tileManager, Unit unit,
Tile start, Tile end, bool ignoreHeight);
public bool IsTileWithinAbilityRange(Unit currentUnit, Unit targetUnit, Ability ability);
}Movement Rules:
- Units can pass through allies but not end movement on occupied tiles
- Units cannot pass through enemies
- Height differences limited by
unit.jumpUpandunit.jumpDown - Pathfinding uses Manhattan distance heuristic
Example: Find Path
Pathfinder pathfinder = new Pathfinder();
TileManager tileManager = BattleStateManager.Instance.tileManager;
List<Tile> path = pathfinder.FindPath(
tileManager,
unit, // Unit moving
startTile, // Current position
endTile, // Destination
new List<Tile>(), // Empty = search all tiles
false // Don't ignore height
);
if (path.Count > 0)
{
// Move along path
foreach (Tile tile in path)
{
// Move to tile.transform.position
}
}Height Mechanics
Units have jump capabilities:
public int jumpUp; // Max tiles can jump UP
public int jumpDown; // Max tiles can jump DOWNExample:
- Knight:
jumpUp = 2,jumpDown = 3 - Can jump from ground to 2-tile-high platform
- Can drop from 3-tile-high cliff to ground
- Cannot reach 3-tile-high platform without stairs
Height in Abilities:
public int MaxVerticalRange; // Max height difference for ability
public bool ignoresHeight; // Ability ignores height restrictionsRange Calculation
Range Class
Calculates movement and ability range.
public class Range
{
public List<Tile> GetTilesWithinRange(Tile fromTile, int minRange, int maxRange,
Unit unit, bool ignoreHeight);
public List<Tile> GetReachableTiles(Tile fromTile, int minRange, int maxRange,
Unit unit, bool ignoreHeight);
}Two Methods:
GetTilesWithinRange- Fast expansion-based range (ignores obstacles)GetReachableTiles- Accurate pathfinding-based range (respects obstacles)
When to Use:
- GetTilesWithinRange: Ability range (magic can target through walls)
- GetReachableTiles: Movement range (units must path around obstacles)
Example: Movement Range
Range range = new Range();
List<Tile> moveTiles = range.GetReachableTiles(
unit.currentTile,
1, // Min range (must move at least 1 tile)
unit.move, // Max range (unit's movement stat)
unit,
false // Respect height
);
// Show blue overlay on moveTiles
foreach (Tile tile in moveTiles)
{
tile.Show();
tile.SetStatus(Tile.TileStatus.Passable);
}Example: Ability Range
Range range = new Range();
List<Tile> abilityTiles = range.GetTilesWithinRange(
unit.currentTile,
ability.GetMinRange(unit),
ability.GetMaxRange(unit),
unit,
ability.ignoresHeight
);
// Show yellow overlay on abilityTiles
foreach (Tile tile in abilityTiles)
{
tile.Show();
tile.SetStatus(Tile.TileStatus.InAbilityRange);
}Grid Setup
Creating the Grid
-
Create Tilemap
- Right-click Hierarchy > 2D Object > Tilemap > Rectangular
- This creates
GridwithTilemapchild
-
Paint Tiles
- Window > 2D > Tile Palette
- Create tiles and paint your battle grid
-
Add Height
- Paint on different Z-levels for elevation
- Z=0: Ground level
- Z=1: 1-tile elevation
- Z=2: 2-tile elevation
-
Add TileManager
- Create empty GameObject named
Tile Manager - Add TileManager component
- Assign Tilemap reference
- Assign Tile Prefab (provided by Wayfinder)
- Create empty GameObject named
Example Tilemap Structure
Grid (GameObject)
├── Layer: Z=0 (Ground)
│ └── Tiles: Floor tiles
├── Layer: Z=1 (Elevation +1)
│ └── Tiles: Raised platforms
└── Layer: Z=2 (Elevation +2)
└── Tiles: High cliffsPerformance Tips
Pathfinding Optimization
Wayfinder’s pathfinding is efficient, but for large maps:
Limit search space:
// Only search within movement range
List<Tile> searchSpace = GetTilesWithinRange(start, 0, unit.move + 5, unit, false);
List<Tile> path = pathfinder.FindPath(tileManager, unit, start, end, searchSpace, false);Cache paths:
// Cache AI pathfinding results
Dictionary<(Tile, Tile), List<Tile>> pathCache = new Dictionary<(Tile, Tile), List<Tile>>();Tile Lookup Optimization
TileManager uses Dictionary<Vector2Int, Tile> for O(1) tile lookups:
// Fast lookup
Tile tile = tileManager.map[new Vector2Int(x, y)];
// Check if tile exists
if (tileManager.map.ContainsKey(new Vector2Int(x, y)))
{
Tile tile = tileManager.map[new Vector2Int(x, y)];
}Next Steps
Last updated on