Skip to content

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:

  • GeometryRootGeometry;
  • PresentationRootPresentation;
  • optional NavigationRegion → tatsächliche NavigationRegion3D.

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, üblich north, east, south, west;
  • Direction: passende RoomDoorDirection;
  • Width 4 m und Height 3 m gemäß Standard;
  • IsOptional: normalerweise true;
  • WallPlug oder WallPlugScene (Rooms/Prefabs/RoomWallPlug3D.tscn);
  • WallPlugCollision, wenn RequiresWallPlugCollision true;
  • NavigationBlocker und 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 StableId boss_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

  1. F6 auf Features/Dungeons/Rooms/Preview/RoomTemplatePreview.tscn.
  2. Template wählen; Validation muss OK sein.
  3. 0/90/180/270° und jeden Socket Open/Sealed prüfen.
  4. Collision im Debug-Visible-Collision-Modus und Navigation kontrollieren.
  5. F6 auf Rooms/Integration/DungeonTemplateIntegrationTest.tscn mit TestSeed = template-integration-01.
  6. Log auf TemplateId, Rotation, Open-Sockets und stabilen DungeonHash prüfen.
  7. Einen normalen Gameflow mit Developer-Seed starten; bei Bedarf RoomPresentationMode = GeneratedFallback zum 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.