diff --git a/Content/Dungeon/DataTable/DT_RoomPool.uasset b/Content/Dungeon/DataTable/DT_RoomPool.uasset new file mode 100644 index 0000000..7a06f6d Binary files /dev/null and b/Content/Dungeon/DataTable/DT_RoomPool.uasset differ diff --git a/Content/Dungeon/Generierung/BP_DungeonGenerator.uasset b/Content/Dungeon/Generierung/BP_DungeonGenerator.uasset index 0eece54..1a05f79 100644 Binary files a/Content/Dungeon/Generierung/BP_DungeonGenerator.uasset and b/Content/Dungeon/Generierung/BP_DungeonGenerator.uasset differ diff --git a/Content/Dungeon/Rooms/BP_Room_Corridor.uasset b/Content/Dungeon/Rooms/BP_Room_Corridor.uasset index cd93239..3d5f972 100644 Binary files a/Content/Dungeon/Rooms/BP_Room_Corridor.uasset and b/Content/Dungeon/Rooms/BP_Room_Corridor.uasset differ diff --git a/Content/Dungeon/Rooms/BP_Room_DeadEnd.uasset b/Content/Dungeon/Rooms/BP_Room_DeadEnd.uasset index 7cd17a6..f054e0d 100644 Binary files a/Content/Dungeon/Rooms/BP_Room_DeadEnd.uasset and b/Content/Dungeon/Rooms/BP_Room_DeadEnd.uasset differ diff --git a/Content/Dungeon/Rooms/BP_Room_Entrance.uasset b/Content/Dungeon/Rooms/BP_Room_Entrance.uasset index e87177c..30ddc62 100644 Binary files a/Content/Dungeon/Rooms/BP_Room_Entrance.uasset and b/Content/Dungeon/Rooms/BP_Room_Entrance.uasset differ diff --git a/Content/Dungeon/Rooms/BP_Room_Exit.uasset b/Content/Dungeon/Rooms/BP_Room_Exit.uasset index 80213ca..b30274d 100644 Binary files a/Content/Dungeon/Rooms/BP_Room_Exit.uasset and b/Content/Dungeon/Rooms/BP_Room_Exit.uasset differ diff --git a/Content/Dungeon/Rooms/BP_Room_General.uasset b/Content/Dungeon/Rooms/BP_Room_General.uasset index 1557e6f..ff92e23 100644 Binary files a/Content/Dungeon/Rooms/BP_Room_General.uasset and b/Content/Dungeon/Rooms/BP_Room_General.uasset differ diff --git a/Content/Dungeon/Rooms/BP_Room_PortalIn.uasset b/Content/Dungeon/Rooms/BP_Room_PortalIn.uasset index f1b6c91..df48b15 100644 Binary files a/Content/Dungeon/Rooms/BP_Room_PortalIn.uasset and b/Content/Dungeon/Rooms/BP_Room_PortalIn.uasset differ diff --git a/Content/Dungeon/Rooms/BP_Room_PortalOut.uasset b/Content/Dungeon/Rooms/BP_Room_PortalOut.uasset index a6e4beb..1120082 100644 Binary files a/Content/Dungeon/Rooms/BP_Room_PortalOut.uasset and b/Content/Dungeon/Rooms/BP_Room_PortalOut.uasset differ diff --git a/Content/Dungeon/Rooms/BP_Room_TShape.uasset b/Content/Dungeon/Rooms/BP_Room_TShape.uasset index 5aa0a7e..6d2d119 100644 Binary files a/Content/Dungeon/Rooms/BP_Room_TShape.uasset and b/Content/Dungeon/Rooms/BP_Room_TShape.uasset differ diff --git a/Planung/plan_v1.md b/Planung/plan_v1.md index 8c5fc83..bc1e4ad 100644 --- a/Planung/plan_v1.md +++ b/Planung/plan_v1.md @@ -98,6 +98,54 @@ Speichert Informationen über jeden platzierten Raum zentral im Generator. | MinLevel | Integer | Ab welchem Level verfügbar | | MaxLevel | Integer | Bis welchem Level (0 = unbegrenzt) | +#### DT_RoomPool erstellen (Data Table im Editor) + +Die Data Table `DT_RoomPool` ist die zentrale Tabelle, aus der der Generator zur Laufzeit Räume auswählt. Sie basiert auf dem Struct `S_RoomPoolEntry`. + +**Voraussetzung:** Der Struct `S_RoomPoolEntry` muss bereits existieren (siehe oben). + +**Schritt 1 – Data Table Asset anlegen:** + +1. Im Content Browser: Rechtsklick → **Miscellaneous** → **Data Table** +2. Im Popup **"Pick Row Structure"**: Wähle **S_RoomPoolEntry** als Row Structure +3. Bestätige mit **OK** +4. Benenne das neue Asset: **DT_RoomPool** +5. Speichere es z.B. unter `Content/Data/DT_RoomPool` (oder einem Ordner deiner Wahl) + +**Schritt 2 – Zeilen hinzufügen:** + +Öffne DT_RoomPool per Doppelklick. Die Tabelle ist zunächst leer. + +1. Klicke oben links auf **Add** (+ Symbol), um eine neue Zeile hinzuzufügen +2. Vergib einen eindeutigen **Row Name** (z.B. "General_01", "Corridor_01", "DeadEnd_01") +3. Befülle die Felder der Zeile: + +| Feld | Was eintragen | Hinweis | +|---|---|---| +| RoomClass | Blueprint-Klasse auswählen (z.B. BP_DungeonRoom_General) | Klick auf das Dropdown → Blueprint-Class wählen | +| RoomType | Passenden Enum-Wert wählen (z.B. General) | Muss zum Blueprint passen | +| Weight | Gewichtung als Float (z.B. 1.0) | Höher = häufiger gewählt | +| MinLevel | Ab welchem Level verfügbar (z.B. 1) | 1 = ab dem ersten Level | +| MaxLevel | Bis welchem Level (z.B. 0) | 0 = unbegrenzt / auf allen Levels | + +**Schritt 3 – Empfohlene Einträge für den Prototyp:** + +| Row Name | RoomClass | RoomType | Weight | MinLevel | MaxLevel | +|---|---|---|---|---|---| +| General_01 | BP_DungeonRoom_General | General | 1.0 | 1 | 0 | +| Corridor_01 | BP_DungeonRoom_Corridor | Corridor | 1.0 | 1 | 0 | +| DeadEnd_01 | BP_DungeonRoom_DeadEnd | DeadEnd | 1.0 | 1 | 0 | + +> **Hinweis:** Entrance, PortalIn, PortalOut und Exit werden **nicht** in die Data Table eingetragen – diese Räume spawnt der Generator direkt per Klasse (hartcodiert in BuildLevel / PlaceEndRoom). Nur Räume, die per Zufallswahl platziert werden (General, Corridor, DeadEnd), gehören hier rein. + +> **Tipp:** Du kannst später weitere Zeilen hinzufügen (z.B. General_02, General_03 mit verschiedenen Gewichtungen oder Level-Bereichen), um mehr Vielfalt zu erzeugen. + +**Schritt 4 – Im Generator referenzieren:** + +Im BP_DungeonGenerator: Die Variable `RoomPoolTable` (Typ: Data Table Reference) auf **DT_RoomPool** setzen. Das geschieht im Details Panel unter dem Default Value: +1. Wähle die Variable `RoomPoolTable` aus +2. Im Details Panel → Default Value → Dropdown → wähle **DT_RoomPool** + ### 1.3 Was wird gelöscht/ersetzt - **S_SocketData** bleibt in den Räumen, wird aber auf **S_SocketDefinition** reduziert (nur noch statische Daten) @@ -848,32 +896,50 @@ Rückwärts iterieren verhindert Index-Verschiebung beim Entfernen! **Schritt 1 – Gültige Kandidaten aus der Data Table filtern:** -1. → **Get Data Table Rows** (Table: RoomPoolTable) → AllRows (Array of S_RoomPoolEntry) -2. → Lokales Array **ValidCandidates** (Typ: Array of S_RoomPoolEntry) -3. → **ForEachLoop** über AllRows -4. → Array Element → **Break S_RoomPoolEntry** → RoomType, MinLevel, MaxLevel +**Lokale Variablen (in der Funktion anlegen):** +- **RowNames** (Array of Name) – Zeilennamen aus der Data Table +- **ValidCandidates** (Array of S_RoomPoolEntry) – gefilterte Kandidaten +- **TotalWeight** (Float) – Summe aller Weights +- **RandomPick** (Float) – zufälliger Wert zwischen 0 und TotalWeight +- **RunningWeight** (Float) – laufende Summe beim Iterieren +- **ChosenEntry** (S_RoomPoolEntry) – der gewählte Kandidat +- **TempCandidate** (Actor Object Ref) – temporär gespawnter Raum für Socket-Matching + +> **Wichtig:** In UE5 gibt es keinen "Get Data Table Rows"-Node (Plural). Stattdessen holst du zuerst alle Zeilennamen mit **Get Data Table Row Names**, dann iterierst du darüber und holst jede Zeile einzeln mit **Get Data Table Row**. + +1. → **Get Data Table Row Names** (Table: RoomPoolTable) → Set **RowNames** +2. → **ForEachLoop** über RowNames +3. → **Get Data Table Row** (Table: RoomPoolTable, Row Name: Array Element) → hat zwei Exec-Pins und einen Data-Pin: + - **Row Found ▶** (Exec) – Zeile existiert + - **Row Not Found ▶** (Exec) – Zeile nicht gefunden (einfach ignorieren, weiter zur nächsten Iteration) + - **Out Row** (S_RoomPoolEntry) – die Zeilendaten +4. → **Row Found ▶**: Out Row → **Break S_RoomPoolEntry** → RoomType, MinLevel, MaxLevel 5. → **Branch**: Drei Bedingungen müssen ALLE true sein (AND): - RoomType → **Contains** in ExcludeTypes Array → **NOT** (= RoomType ist NICHT ausgeschlossen) - MinLevel **<=** CurrentLevel - MaxLevel **>=** CurrentLevel **OR** MaxLevel == 0 (0 = unbegrenzt) -6. → True ▶: **Add** Array Element zu ValidCandidates +6. → True ▶: Out Row → **Add** zu ValidCandidates 7. → ForEachLoop Completed ▶: **Branch** (ValidCandidates **Length > 0**) 8. → False ▶: **Return** (Success = false) ``` -Get Data Table Rows → ForEachLoop - → Branch: NOT Contains(ExcludeTypes, RoomType) - AND MinLevel <= CurrentLevel - AND (MaxLevel >= CurrentLevel OR MaxLevel == 0) - True ▶ → Add zu ValidCandidates - Completed ▶ → Branch: Length > 0? +Get Data Table Row Names (RoomPoolTable) → RowNames +ForEachLoop (RowNames) + Loop Body ▶ → Get Data Table Row (RoomPoolTable, Array Element) + Row Found ▶ → Break S_RoomPoolEntry → RoomType, MinLevel, MaxLevel + → Branch: NOT Contains(ExcludeTypes, RoomType) + AND MinLevel <= CurrentLevel + AND (MaxLevel >= CurrentLevel OR MaxLevel == 0) + True ▶ → Add zu ValidCandidates + Row Not Found ▶ → (nichts, nächste Iteration) + Completed ▶ → Branch: ValidCandidates Length > 0? False ▶ → Return (Success = false) True ▶ → (weiter mit Schritt 9) ``` **Schritt 9 – Gewichtete Zufallswahl:** -9. → **TotalWeight** = 0.0 (lokale Float-Variable) +9. → **Set TotalWeight** = 0.0 10. → **ForEachLoop** über ValidCandidates → TotalWeight += Array Element → Weight 11. → **Random Float in Range** (0.0, TotalWeight) → **Set** RandomPick 12. → **Set** RunningWeight = 0.0 @@ -905,12 +971,15 @@ Wir müssen herausfinden, welcher Socket des neuen Raums als "Eingang" benutzt w 19. → **Branch**: SocketDefinitions **Length > 0**? - False ▶: TempCandidate → **Destroy Actor** → **Return** (Success = false) 20. → True ▶: SocketDefinitions **Get (Index 0)** → Break S_SocketDefinition -21. → **Set MatchingSocketIndex** = 0 -22. → **Set MatchingSocketId** = SocketId (aus dem Break) -23. → **Set FoundRoomType** = ChosenEntry → RoomType -24. → **Set FoundRoomClass** = ChosenEntry → RoomClass -25. → TempCandidate → **Destroy Actor** -26. → **Return** (FoundRoomClass, MatchingSocketIndex, MatchingSocketId, FoundRoomType, Success = true) +21. → TempCandidate → **Destroy Actor** +22. → **Return Node** – die Output-Pins direkt am Return Node verdrahten: + - FoundRoomClass ← ChosenEntry → Break S_RoomPoolEntry → RoomClass + - MatchingSocketIndex ← 0 (Integer Literal) + - MatchingSocketId ← Break S_SocketDefinition → SocketId (aus Schritt 20) + - FoundRoomType ← ChosenEntry → Break S_RoomPoolEntry → RoomType + - Success ← true (Boolean Literal) + +> **Hinweis:** In UE5 Funktionen haben die Outputs keine separaten Set-Nodes — sie sind direkt als Data-Pins am Return Node. Du ziehst die Daten-Verbindungen (grüne/blaue Drähte) direkt in die Pins des Return Nodes. Die Exec-Kette ist: SpawnActor ▶ → GetSocketDefinitions ▶ → Branch → True ▶ → Destroy Actor ▶ → Return. **Spätere Erweiterung – Richtungs-Matching:** Statt pauschal Socket 0 zu nehmen, könnte man die Richtung des offenen Sockets prüfen und den Socket des Kandidaten wählen, der in die entgegengesetzte Richtung zeigt (Nord → Süd, Ost → West). Das ist aber für den Prototyp nicht nötig.