8. Auto-Tiling System
Implementeer intelligent road auto-tiling met neighbor detection
Overzicht
In dit hoofdstuk leer je:
NESW neighbor detection (North, East, South, West)
String-based pattern matching voor tile types
Orientation lookup table met Dictionary
IsRoadTile() helper method
Dynamic tile updates bij placement/removal
Waarom Auto-Tiling?
Tot nu toe plaatst het systeem altijd het straight road tile (ID 13). Dit ziet er niet realistisch uit bij corners en junctions!
Het probleem:
Straight road op corners → ziet er verkeerd uit
Straight road op T-junctions → geen verbinding
Straight road op intersections → chaotisch
De oplossing: Auto-Tiling
Detecteer hoeveel neighbors een road tile heeft (0-4)
Detecteer welke kant de neighbors zitten (North/East/South/West)
Selecteer automatisch het juiste tile type (straight/corner/T/intersection)
Update automatisch de orientation
MeshLibrary tile IDs:
13: Straight road
10: Corner road
12: T-junction road
11: Intersection (4-way)
Deze tiles worden automatisch geselecteerd op basis van neighbors!
Tile ID exports toevoegen
Vervang de simpele RoadTileId door aparte exports voor elk tile type.
Verwijder de oude exports:
VERWIJDER DEZE REGELS:
Voeg nieuwe exports toe voor alle tile types. Gebruik een ExportGroup om ze te groeperen in de Inspector.
ExportGroup:
Groepeert gerelateerde exports in de Inspector
Maakt configuratie overzichtelijker
Optioneel - werkt ook zonder, maar ziet er professioneler uit
Sla het script op!
Directions array en lookup table
Maak een array voor neighbor directions en een Dictionary voor orientation lookups.
Nieuwe C#-specifieke elementen:
readonly- Field kan alleen in declaratie of constructor worden ingesteldDe array wordt eenmalig ingesteld en verandert nooit
Voorkomt bugs (kan niet per ongeluk overschreven worden)
Compiler optimalisatie
Voeg een directions array toe. Deze array bevat de vier NESW (North, East, South, West) offset vectors.
Voeg een Dictionary toe die een patroon koppelt aan een richting. Bijvoorbeeld:
"1010"→ North-South,"0101"→ East-West.
Voeg patronen toe voor de rechte wegen. Een string zoals
"1010"betekent: North=yes, East=no, South=yes, West=no.Elk karakter is een richting: North, East, South, West
"1"= road neighbor aanwezig"0"= geen road neighbor"1010"= North + South = verticale road (orientation 0)"0101"= East + West = horizontale road (orientation 16)
Voeg patronen toe voor de bochten.
Elk corner heeft een specifieke orientation (10, 16, 0, 22)
Deze komen overeen met 90° rotaties in de GridMap
Voeg patronen toe voor de T-kruispunten.
Voeg het patroon toe voor een gewoon kruispunt.
Sla het script op
IsRoadTile helper method
Maak een helper method om te checken of een tile ID een road is.
Voeg een lege
IsRoadTile()method toe onderaan de class:
Check of de tile ID in het road range valt. Alle road tiles hebben IDs tussen 10 en 14.
Range check:
ID 10 = Corner
ID 11 = Intersection
ID 12 = T-junction
ID 13 = Straight
ID 14 = Straight (alternatief)
Simpeler dan
tileId == StraightId || tileId == CornerId || ...
Sla het script op
GetTileIdFromKey implementeren
Maak een method om het juiste tile type te bepalen op basis van het neighbor pattern.
Nieuwe C#-specifieke elementen:
Count()- LINQ method om elementen te tellen die aan een conditie voldoen
Voeg bovenaan een nieuw using statement toe om LINQ te kunnen gebruiken
Voeg een lege
GetTileIdFromKey()method toe:
Tel het aantal connections. Tel hoeveel
'1'karakters in de string zitten.
LINQ Count:
key.Count(c => c == '1')telt alle karakters die'1'zijn"1010"→ 2 connections"1111"→ 4 connectionsLambda expressie:
c => c == '1'betekent "elk karakter c waar c gelijk is aan '1'"
Voeg een switch statement toe om het tile type te bepalen:
Voeg de 4-connection case toe (intersection):
Voeg de 3-connection case toe (T-junction):
Voeg de 2-connection case toe (straight of corner). Check of de neighbors opposite zijn voor straight, anders corner:
2-connection logica:
"1010"(N+S) of"0101"(E+W) = opposite neighbors = StraightAlle andere 2-connection patterns = adjacent neighbors = Corner
if/elseom tussen beide te kiezen
Voeg de default case toe (0-1 connections):
Sla het script op!
UpdateRoadTile implementeren
Maak een method om een enkele road tile te updaten op basis van zijn neighbors.
Voeg een lege
UpdateRoadTile()method toe:
Check de vier neighbors. Voor elke richting, check of er een road is (1) of niet (0).
Neighbor detection:
Haal het tile ID op van elke neighbor cel
Check met IsRoadTile() of het een road is
Converteer bool naar int (1 of 0) met ternary operator
Bouw de pattern string. Concateneer de 4 integers tot een string zoals
"1010".
String interpolation:
$"{n}{e}{s}{w}"combineert de 4 integers tot één stringVoorbeeld: n=1, e=0, s=1, w=0 →
"1010"
Zoek de orientation op in de Dictionary. Als het pattern niet bestaat, vervang de road door grass.
TryGetValue:
Probeert de key op te zoeken in de Dictionary
Als gevonden:
orientationbevat de waarde, returntrueAls niet gevonden: return
falseVeiliger dan
RoadOrientations[key](die gooit exception bij missing key)
Bepaal het tile type en update de cel:
Final update:
GetTileIdFromKey(key)bepaalt welk tile type (straight/corner/T/intersection)SetCellItem(cell, tileId, orientation)plaatst het tile met de juiste rotatie
Sla het script op!
UpdateSurroundingTiles implementeren
Maak een method om alle neighbors van een cel te updaten.
Voeg een lege
UpdateSurroundingTiles()method toe:
Loop door alle 4 neighbors. Update elk neighbor als het een road is.
Neighbor propagatie:
Loop door N, E, S, W directions
Check of de neighbor een road is
Zo ja: update de tile (kan van straight naar corner veranderen, etc.)
Update ook de center cell zelf (als het een road is):
Center update:
Wanneer je een road plaatst, moet de nieuwe road ook geüpdatet worden
Wanneer je een road verwijdert, is centerCell grass (IsRoadTile = false)
Check voorkomt onnodige updates
Sla het script op!
Build() en Remove() updaten
Integreer auto-tiling in de placement en removal methods.
Pas de
Build()method aan. Voeg auto-tiling toe na placement.
Vervang:
Door:
Build flow:
Plaats het straight road tile (ID 13)
UpdateSurroundingTiles() update de nieuwe road + alle 4 neighbors
Auto-tiling gebeurt automatisch!
Pas de
Remove()method aan. Vervang de hele method door een helper call.
Vervang:
Door:
Voeg de
TryRemoveRoad()helper method toe:
Remove flow:
Check of de cel een road is (met IsRoadTile helper)
Vervang door grass
UpdateSurroundingTiles() update alle 4 neighbors
Debug print als je probeert een niet-road te verwijderen
Sla het script op!
CanBuild() updaten
Pas de grass check aan om de nieuwe GrassTileId te gebruiken.
Pas CanBuild() aan om GrassTileId te gebruiken:
Vervang:
Geen wijziging nodig! De method gebruikt al GrassTileId, dus het werkt al met de nieuwe export.
Sla het script op!
Testen
Test alle tile types en orientations.
Druk F5 om het spel te runnen.
Test 1: Straight roads
Selecteer de road tile in de UI (6e tile)
Plaats twee verticale roads boven elkaar → blijven straight
Plaats twee horizontale roads naast elkaar → blijven straight
Test 2: Corner roads
Plaats een L-vormig pad
De corner tile verschijnt automatisch met de juiste orientation
Test alle 4 corner varianten (NE, ES, SW, NW)
Test 3: T-junctions
Plaats een straight road
Voeg een road toe aan de zijkant → T-junction verschijnt
Test alle 4 T-junction orientations
Test 4: Intersection
Maak een T-junction
Voeg een road toe aan de vierde kant → intersection verschijnt
Test 5: Dynamic updates
Maak een intersection (4-way)
Verwijder één road → wordt een T-junction
Verwijder nog een road → wordt een corner
Verwijder nog een road → wordt straight
Alle updates gebeuren automatisch!
Test 6: Isolated roads
Plaats een enkele road → straight tile (0-1 connections)
Plaats een road ernaast → beide worden straight (2 connections opposite)
Werkt alles? Sluit het spel (F8)
Veelgemaakte fouten
Lookup table KeyNotFoundException: Dit gebeurt als een pattern niet in de Dictionary zit. Check of je alle patterns hebt toegevoegd (straight, corner, T, intersection). De
TryGetValue()check voorkomt dit - als je toch errors ziet, check of je TryGetValue gebruikt.Verkeerde tile IDs: De IDs zijn 10-13, niet 14-17. Check je exports in de Inspector (Straight=13, Corner=10, T-junction=12, Intersection=11).
Tiles updaten niet: Vergeet niet
UpdateSurroundingTiles()aan te roepen in beideBuild()enRemove().IsRoadTile() geeft verkeerde resultaten: De range check is
>= 10 && <= 14. Als je andere tile IDs gebruikt, pas de range aan.Pattern string is verkeerd: Check dat je
$"{n}{e}{s}{w}"gebruikt (NESW volgorde). Een verkeerde volgorde geeft verkeerde patterns.
Volledig script
Laatst bijgewerkt