How-to: Dungeon-Raum erstellen
Status: aktiver V3-Template-Workflow
1. Passenden Ausgangspunkt wählen
Das Skelett liegt in src/HolodeckArena.Game3D/Features/Dungeons/Rooms/Templates/examples/RoomTemplate_Blank.tscn. Für einen V3-Raum ist meist das vorhandene Template derselben Matrixposition der bessere Start, etwa RoomTemplate_CombatSmall_Example01.tscn: Der Blank-Raum hat Default-Metadaten und nur einen North-Socket und ist nicht direkt kataloggültig.
Kopiere die Scene im Godot FileSystem-Dock, damit UIDs/Subresources korrekt behandelt werden. Benenne RoomTemplate_<Type>_<Name><NN>.tscn; TemplateId bleibt lowercase snake_case, zum Beispiel combat_small_reactor_01. IDs nicht später umbenennen, sobald Replays/Seeds sie referenzieren können.
2. Kategorie, Rolle und Maße festlegen
Am RoomTemplate3D-Root eine RoomTemplateMetadata-Resource setzen:
| V3-Zweck | Category | Size | GameplayRole | LogicalWidth×Height |
|---|---|---|---|---|
| Start | Start | Small | StartLounge |
18×12 |
| kleiner Kampf | Combat | Small | SmallRoom |
22×16 |
| großer Kampf | Combat | Large | LargeRoom |
34×24 |
| Treasure | Treasure | Small | TreasureRoom |
20×16 |
| Boss | Boss | BossArena | BossRoom |
40×30 |
| Exit | Exit | Medium | ExitRoom |
24×16 |
Zusätzlich TemplateId, DisplayName, SelectionWeight > 0, Tags, AllowedThemes und MinDepth/MaxDepth setzen. Die aktive Auswahl wertet Themes/Tags/Difficulty noch nicht aus; Depth und Weight schon.
3. Koordinaten, Pivot und Bounds
Root-Pivot ist Bodenmitte bei Y=0. North = −Z, East = +X, South = +Z, West = −X. Ein logisches Feld entspricht DungeonWorldMetrics3D.MetersPerCell = 2 m. Die Metadatenmaße sind der Template-Slot; kanonische GridRectangle-Bounds zählen Ränder inklusive und werden im Request deshalb als Bounds.Width - 1/Height - 1 abgebildet.
Geometrie muss innerhalb der halben Maße liegen. Bodenoberkante konsistent bei Y=0 halten; Player/Gegner stehen über dem Boden. RoomBoundsPreview3D visualisiert Bounds im Editor, ersetzt aber keine Collision.
4. Node-Struktur
Root-Script RoomTemplate3D.cs. Weise mindestens zu:
GeometryRoot→Geometry;PresentationRoot→Presentation;- optional
NavigationRegion→ tatsächlicheNavigationRegion3D.
Empfohlene vorhandene Gruppen: Geometry, Collision, Navigation, Doors, GameplayMarkers/EnemySpawns, CoverPoints, PlayerSpawns, InteractionPoints, DecorationMarkers, Lighting, Presentation, Debug. Node-Namen helfen dem Editor; die Runtime sammelt Marker nach Typ, nicht Gruppennamen.
Geometrie unter Geometry, statische StaticBody3D/CollisionShape3D unter Collision. Collision an Boden/Wänden/Türrahmen prüfen; keine doppelte globale Fallback-Geometrie im Template-Modus. Navigationregion/-mesh so konfigurieren, dass sealed WallPlugs nicht durchlaufbar sind. Der aktuelle Gegner nutzt zusätzlich DungeonGridNavigator3D, daher beides testen.
5. Door-Sockets
Für jede mögliche Richtung einen RoomDoorSocket3D unter Doors. Exportwerte:
SocketId: innerhalb der Scene eindeutig, üblichnorth,east,south,west;Direction: passendeRoomDoorDirection;Width4 m undHeight3 m gemäß Standard;IsOptional: normalerweise true;WallPlugoderWallPlugScene(Rooms/Prefabs/RoomWallPlug3D.tscn);WallPlugCollision, wennRequiresWallPlugCollisiontrue;NavigationBlockerund optional DebugVisual.
Position exakt auf der Raumgrenze, Öffnung vollständig innerhalb der Kante. Local −Z/Vector3.Forward des Marker-Transforms muss nach außen zeigen. Der Validator verlangt Dot ≥ 0,95. Zwei Sockets dürfen nicht denselben ConnectionPoint belegen.
Zur Laufzeit prüft RoomDoorSocketAssignment.ResolveState Rotation und kanonisch verbundene Weltrichtungen. Open blendet Plug aus/deaktiviert Collision und NavigationBlocker; alle nicht benötigten Sockets werden Sealed. RuntimeDoor3D wird separat einmal pro Verbindung erzeugt und steuert Encounterlocks. Keine animierte Tür in den Socket einbauen, ohne dieses Ownership-Modell zu ändern.
6. Gameplay-Marker
Alle Marker brauchen eindeutige StableId-Werte:
- Combat: mindestens
EnemySpawnMarker3D; konfigurierbar sind SpawnGroup, Priority, AllowedEnemyTags, Difficulty, Radius, ActivationProbability. Die aktive Factory nutzt davon derzeit nur Transform/StableId. - Boss: mindestens
BossSpawnMarker3D; verwende nach Möglichkeit StableIdboss_spawn, weil die Factory diesen bevorzugt. - Start: mindestens
PlayerSpawnMarker3D. - Exit: mindestens
InteractionMarker3D. - Treasure: InteractionMarker oder RoomCenter, da die Chest diese Positionen bevorzugt.
- optional: Cover, Decoration, RoomCenter, CameraFocus.
Keinen LootSpawnMarker anlegen: Ein solcher Typ existiert nicht. Treasure-Chests werden in DungeonRun3DController.CreateTreasureChests an Interaction/Center erzeugt. Encounter-Area-Nodes sind ebenfalls nicht Teil des aktuellen Vertrags; Raumaktivierung geschieht durch DungeonRoomTracker3D anhand kanonischer Bounds.
7. Katalog registrieren
Öffne Features/Dungeons/Rooms/Metadata/RoomTemplateCatalogV3.tres, füge die PackedScene zu Templates hinzu und lasse bestehende Einträge stehen. Details: Raumtemplate registrieren. Exakte Matrix-Coverage muss weiterhin vorhanden sein.
8. Lokal validieren
- F6 auf
Features/Dungeons/Rooms/Preview/RoomTemplatePreview.tscn. - Template wählen; Validation muss OK sein.
- 0/90/180/270° und jeden Socket Open/Sealed prüfen.
- Collision im Debug-Visible-Collision-Modus und Navigation kontrollieren.
- F6 auf
Rooms/Integration/DungeonTemplateIntegrationTest.tscnmitTestSeed = template-integration-01. - Log auf TemplateId, Rotation, Open-Sockets und stabilen DungeonHash prüfen.
- Einen normalen Gameflow mit Developer-Seed starten; bei Bedarf
RoomPresentationMode = GeneratedFallbackzum Eingrenzen Template-vs.-Generator vergleichen.
9. Tests ergänzen
In tests/HolodeckArena.Game3D.Tests/RoomTemplateSelectorTests.cs Kandidat/Rotation/Bounds/Doors/Seed prüfen, wenn neue Auswahlregeln entstehen. Socket-/Plug-Regeln in RoomDoorSocketTests.cs. Eine reine neue Artvariante mit unveränderten Regeln braucht mindestens Preview und Integrationstest; ein automatischer Godot-Resource-Existenztest ist als Lücke dokumentiert.
Häufige Fehler
- No compatible template: Role/Size/LogicalWidth/Height exakt gegen Fehler prüfen; 90° dreht Maße.
- Socket outside boundary: Position oder Metadata-Maße falsch.
- Forward does not point outward: Marker-Yaw/Basis falsch.
- Missing WallPlug collision: NodePath/Shape fehlt oder PlugScene anders aufgebaut.
- Enemy/Boss spawnt nicht: Pflichtmarker fehlt, StableId doppelt oder Objective enthält keine EnemyInstance für den Raum.
- Unsichtbare Wand in Öffnung: doppelte Collision oder Socket bleibt Sealed.
- Tür doppelt: animierte Template-Tür plus RuntimeDoor.
- Player fällt/spawnt versetzt: Pivot/Bodenhöhe/PlayerSpawn-Marker falsch.
- Nur ein Template: gültig; derselbe PackedScene-Eintrag wird für alle passenden Räume als getrennte Instanz wiederverwendet.
Checkliste
- [ ] stabile TemplateId, Kategorie, Größe, Role und exakte Maße
- [ ] Pivot Bodenmitte Y=0, Geometrie innerhalb Bounds
- [ ] Floor/Wall/Frame-Collision geprüft
- [ ] Door-Sockets auf Grenze, Forward außen, Plug/Collision/Blocker vorhanden
- [ ] rollenabhängige Pflichtmarker und eindeutige IDs
- [ ] kein LootSpawnMarker, keine zweite Door-Ownership
- [ ] Katalogeintrag und Coverage valide
- [ ] Preview alle Rotationen/Sockets
- [ ] Integrationstest mit festem Seed
- [ ] relevante xUnit-Tests und Dokumentation aktualisiert
Verwandt: Systemseite, Troubleshooting, Änderungsmatrix.