diff --git a/Assets/Scenes/Dev/WavefunctionCollapseProceduralGeneration.unity b/Assets/Scenes/Dev/WavefunctionCollapseProceduralGeneration.unity index f4a89645..0d820333 100644 --- a/Assets/Scenes/Dev/WavefunctionCollapseProceduralGeneration.unity +++ b/Assets/Scenes/Dev/WavefunctionCollapseProceduralGeneration.unity @@ -166,9 +166,15 @@ MonoBehaviour: branchFrequency: 0.3 branchLengthMin: 2 branchLengthMax: 4 - useCustomStartEnd: 1 - customStartPoint: {x: 1, y: 1} - customEndPoint: {x: 13, y: 13} + startEndPairs: + - start: {fileID: 919478494} + end: {fileID: 350389820} + - start: {fileID: 350389820} + end: {fileID: 919478494} + - start: {fileID: 501085820} + end: {fileID: 1753478022} + - start: {fileID: 1753478022} + end: {fileID: 501085820} enforceMainPath: 1 --- !u!4 &202619012 Transform: @@ -195,7 +201,7 @@ GameObject: m_Component: - component: {fileID: 350389820} m_Layer: 0 - m_Name: PlayerSpawn (2) + m_Name: top right m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -209,7 +215,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 350389819} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 54, y: 0, z: 54} + m_LocalPosition: {x: 13, y: 0, z: 13} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -226,7 +232,7 @@ GameObject: m_Component: - component: {fileID: 501085820} m_Layer: 0 - m_Name: PlayerSpawn (1) + m_Name: top left m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -240,7 +246,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 501085819} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 2, y: 0, z: 54} + m_LocalPosition: {x: 1, y: 0, z: 13} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -421,7 +427,7 @@ GameObject: m_Component: - component: {fileID: 919478494} m_Layer: 0 - m_Name: PlayerSpawn + m_Name: bot left m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -435,7 +441,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 919478493} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 2, y: 0, z: 2} + m_LocalPosition: {x: 1, y: 0, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -786,7 +792,7 @@ GameObject: m_Component: - component: {fileID: 1753478022} m_Layer: 0 - m_Name: PlayerSpawn (3) + m_Name: bot right m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -800,7 +806,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1753478021} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 54, y: 0, z: 2} + m_LocalPosition: {x: 13, y: 0, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -843,31 +849,31 @@ MonoBehaviour: - {fileID: 7255329216686614878, guid: 7dbefec577d5e284fbddd5a29842cc2c, type: 3} - {fileID: 2704001218989138493, guid: 2c83cfd89cb8a284caca24f2ca9d0ba3, type: 3} - {fileID: 2704001218989138493, guid: bd98fb12d63b7bc49ae0f03c2245b435, type: 3} - - {fileID: 2704001218989138493, guid: 6a774c110d5aeb1408324d380adb8955, type: 3} - - {fileID: 2704001218989138493, guid: 3162a96ef13239b41ba3d21ca801cdc4, type: 3} - {fileID: 2704001218989138493, guid: d9e49365637f4444a99840103c5d5a44, type: 3} - {fileID: 2704001218989138493, guid: 80ed2fe86d7677d498f807270b37b1f7, type: 3} - - {fileID: 2704001218989138493, guid: d32ae7acb5c9b0f489ce40dc2e15c772, type: 3} - - {fileID: 7919088255103129344, guid: cc3828d7e55dcf04b85290093563dff2, type: 3} - - {fileID: 7919088255103129344, guid: 2b7862a7ca7290d4c922cecdd20528bb, type: 3} - - {fileID: 7919088255103129344, guid: 31934c838854a3c4baa7ad791fd520d3, type: 3} - - {fileID: 7919088255103129344, guid: 1e236b387bdb75c4ab929f783d7e3f24, type: 3} - - {fileID: 7919088255103129344, guid: 2653cb9ee3eaab74ca647ba7532e1608, type: 3} - - {fileID: 7919088255103129344, guid: 31dfb5210a9d64b41bb417620dd68533, type: 3} - - {fileID: 7919088255103129344, guid: 2bbd6e86a833c8a4e9ee47a195ec46c1, type: 3} - - {fileID: 7919088255103129344, guid: e2e591d216fb2734aba113997efa3797, type: 3} - - {fileID: 7919088255103129344, guid: 1ff71b2adbd7a854cb82ddfd95f25afb, type: 3} - - {fileID: 2704001218989138493, guid: 10dc33d8ada12f84ebd7234446f34c45, type: 3} + - {fileID: 2704001218989138493, guid: 6a774c110d5aeb1408324d380adb8955, type: 3} + - {fileID: 2704001218989138493, guid: 3162a96ef13239b41ba3d21ca801cdc4, type: 3} - {fileID: 7255329216686614878, guid: a809dc39cad8b27429e59a86867fd6d6, type: 3} - - {fileID: 7919088255103129344, guid: 503e9bc31e02ce046bda52996a26fe22, type: 3} - - {fileID: 7919088255103129344, guid: a057db1023afbb44993f4161fe103b41, type: 3} - - {fileID: 7919088255103129344, guid: 963551cb04192a84088ddaaa3500f559, type: 3} - - {fileID: 7919088255103129344, guid: 09343d8e8bc60e445bae34f6881ffe59, type: 3} - - {fileID: 7919088255103129344, guid: 9a95e856383ff334b8850ad578cb6d65, type: 3} - - {fileID: 7919088255103129344, guid: 55a0e845f95f1974f880c446a4af8303, type: 3} - - {fileID: 2704001218989138493, guid: 989f0d6e8bde6834ebbd740844aeba0e, type: 3} - {fileID: 7919088255103129344, guid: a00c0b36ee4586144a9ec800f0d38830, type: 3} + - {fileID: 2704001218989138493, guid: 989f0d6e8bde6834ebbd740844aeba0e, type: 3} + - {fileID: 7919088255103129344, guid: 55a0e845f95f1974f880c446a4af8303, type: 3} + - {fileID: 7919088255103129344, guid: 9a95e856383ff334b8850ad578cb6d65, type: 3} + - {fileID: 7919088255103129344, guid: 09343d8e8bc60e445bae34f6881ffe59, type: 3} + - {fileID: 7919088255103129344, guid: 963551cb04192a84088ddaaa3500f559, type: 3} + - {fileID: 7919088255103129344, guid: a057db1023afbb44993f4161fe103b41, type: 3} + - {fileID: 7919088255103129344, guid: 503e9bc31e02ce046bda52996a26fe22, type: 3} + - {fileID: 2704001218989138493, guid: 10dc33d8ada12f84ebd7234446f34c45, type: 3} + - {fileID: 7919088255103129344, guid: 2653cb9ee3eaab74ca647ba7532e1608, type: 3} + - {fileID: 7919088255103129344, guid: e2e591d216fb2734aba113997efa3797, type: 3} + - {fileID: 7919088255103129344, guid: 2bbd6e86a833c8a4e9ee47a195ec46c1, type: 3} + - {fileID: 7919088255103129344, guid: 31dfb5210a9d64b41bb417620dd68533, type: 3} - {fileID: 2704001218989138493, guid: 2fce0180ccd18534faacb5e22db086b9, type: 3} + - {fileID: 7919088255103129344, guid: 1e236b387bdb75c4ab929f783d7e3f24, type: 3} + - {fileID: 7919088255103129344, guid: 31934c838854a3c4baa7ad791fd520d3, type: 3} + - {fileID: 7919088255103129344, guid: 2b7862a7ca7290d4c922cecdd20528bb, type: 3} + - {fileID: 7919088255103129344, guid: cc3828d7e55dcf04b85290093563dff2, type: 3} + - {fileID: 2704001218989138493, guid: d32ae7acb5c9b0f489ce40dc2e15c772, type: 3} + - {fileID: 7919088255103129344, guid: 1ff71b2adbd7a854cb82ddfd95f25afb, type: 3} - {fileID: 7919088255103129344, guid: f818560f421c6f348b9d516c62c52d09, type: 3} --- !u!4 &2078654584 Transform: diff --git a/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/TupleTransform.cs b/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/TupleTransform.cs new file mode 100644 index 00000000..f1b878f9 --- /dev/null +++ b/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/TupleTransform.cs @@ -0,0 +1,10 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +[System.Serializable] +public class TupleTransform +{ + public Transform start; + public Transform end; +} diff --git a/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/TupleTransform.cs.meta b/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/TupleTransform.cs.meta new file mode 100644 index 00000000..a4f448f9 --- /dev/null +++ b/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/TupleTransform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb1682e3348aa144885053fa0b89077e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/WFCGenerator.cs b/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/WFCGenerator.cs index 55d84888..73f45db1 100644 --- a/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/WFCGenerator.cs +++ b/Assets/Scripts/-ProceduralGeneration/WavefunctionCollapse/Scripts/WFCGenerator.cs @@ -30,11 +30,9 @@ public class WFCGenerator : MonoBehaviour [SerializeField] private float branchFrequency = 0.3f; [SerializeField] private int branchLengthMin = 2; [SerializeField] private int branchLengthMax = 4; - [Space] - [SerializeField] private bool useCustomStartEnd = false; - [SerializeField] private Vector2Int customStartPoint = new Vector2Int(1, 1); - [SerializeField] private Vector2Int customEndPoint = new Vector2Int(13, 13); + [Space] + [SerializeField] private List startEndPairs = new List(); // Possible spawn points and exit points private Vector2Int startPoint; private Vector2Int endPoint; @@ -47,182 +45,172 @@ public class WFCGenerator : MonoBehaviour private List mainPath = new List(); private HashSet guaranteedConnections = new HashSet(); + bool mainPathReady = false; + bool gridReady = false; + private void Start() { chunkCompatibilityMatrix.BuildCompatibilityMatrix(); - if (randomizeSeed) seed = UnityEngine.Random.Range(0, 1000000); - UnityEngine.Random.InitState(seed); - if (enforceMainPath) - { - GenerateMainPath(); - } + // Generate path first + GenerateMainPath(); + // Then initialize grid with path consideration + //InitializeGrid(); - InitializeGrid(chunkCompatibilityMatrix.prefabs); - GenerateMap(); + // Finally start the WFC process + //await WaitSignal(); + + //StartCoroutine(RunWFC()); } - - private void GenerateMainPath() + private async Task WaitSignal() { - DetermineStartAndEndPoints(); + while (!(mainPathReady && gridReady)) + { + await Task.Delay(delayAwait); + } + } + private async void GenerateMainPath() + { + int startEndIndex = UnityEngine.Random.Range(0, startEndPairs.Count); + startPoint = new Vector2Int((int)startEndPairs[startEndIndex].start.position.x, (int)startEndPairs[startEndIndex].start.position.z); + endPoint = new Vector2Int((int)startEndPairs[startEndIndex].end.position.x, (int)startEndPairs[startEndIndex].end.position.z); - // Start from bottom-left Vector2Int current = startPoint; mainPath.Add(current); - guaranteedConnections.Add(current); - guaranteedConnections.Add(endPoint); while (current != endPoint) { - Vector2Int next = GetNextPathPoint(current, endPoint); - + Vector2Int next = GetNextPathPoint(current); if (!IsOutOfBounds(next) && !mainPath.Contains(next)) { current = next; mainPath.Add(current); - guaranteedConnections.Add(current); - // Add some branching paths - if (UnityEngine.Random.value < branchFrequency) + if (UnityEngine.Random.value < 0.3f) { AddBranchPath(current); } } + await Task.Delay(delayAwait); } + + mainPathReady = true; + + InitializeGrid(); + } + + private Vector2Int GetNextPathPoint(Vector2Int current) + { + Vector2Int direction = endPoint - current; + List possibleMoves = new List(); + + // Always consider all four primary directions + var primaryDirections = new List + { + Vector2Int.up, + Vector2Int.right, + Vector2Int.down, + Vector2Int.left + }; + + // Sort directions by their effectiveness in reaching the target + primaryDirections.Sort((a, b) => + { + float scoreA = Vector2Int.Distance(current + a, endPoint); + float scoreB = Vector2Int.Distance(current + b, endPoint); + return scoreA.CompareTo(scoreB); + }); + + // Add sorted directions to possible moves if they're valid + foreach (var dir in primaryDirections) + { + Vector2Int nextPos = current + dir; + if (IsValidPathPosition(nextPos)) + { + possibleMoves.Add(nextPos); + } + } + + // If no primary moves are available, try diagonal moves + if (possibleMoves.Count == 0) + { + var diagonalDirections = new List + { + new Vector2Int(1, 1), + new Vector2Int(1, -1), + new Vector2Int(-1, 1), + new Vector2Int(-1, -1) + }; + + foreach (var dir in diagonalDirections) + { + Vector2Int nextPos = current + dir; + if (IsValidPathPosition(nextPos)) + { + possibleMoves.Add(nextPos); + } + } + } + + // If we have valid moves, prefer the one that gets us closest to the target + if (possibleMoves.Count > 0) + { + // Sort by distance to target and add some randomness + possibleMoves.Sort((a, b) => + { + float scoreA = Vector2Int.Distance(a, endPoint) + UnityEngine.Random.Range(0f, 0.5f); + float scoreB = Vector2Int.Distance(b, endPoint) + UnityEngine.Random.Range(0f, 0.5f); + return scoreA.CompareTo(scoreB); + }); + + return possibleMoves[0]; + } + + return current; // Only return current position if absolutely no moves are available + } + + private bool IsValidPathPosition(Vector2Int pos) + { + return !IsOutOfBounds(pos) && + !mainPath.Contains(pos) && + pos.x > 0 && pos.x < gridWidth - 1 && + pos.y > 0 && pos.y < gridHeight - 1; } private void AddBranchPath(Vector2Int start) { Vector2Int current = start; - int branchLength = UnityEngine.Random.Range(branchLengthMin, branchLengthMax); + int maxLength = 3; - for (int i = 0; i < branchLength; i++) + for (int i = 0; i < maxLength; i++) { - Vector2Int next; - if (UnityEngine.Random.value < 0.5f) - next = current + Vector2Int.right * (UnityEngine.Random.value < 0.5f ? 1 : -1); - else - next = current + Vector2Int.up; + Vector2Int direction = UnityEngine.Random.value < 0.5f ? + new Vector2Int(UnityEngine.Random.value < 0.5f ? 1 : -1, 0) : + new Vector2Int(0, 1); - if (!IsOutOfBounds(next) && !mainPath.Contains(next) && + Vector2Int next = current + direction; + + if (!IsOutOfBounds(next) && + !mainPath.Contains(next) && next.x > 0 && next.x < gridWidth - 1 && next.y > 0 && next.y < gridHeight - 1) { current = next; - guaranteedConnections.Add(current); + mainPath.Add(current); } else + { break; - } - } - private void DetermineStartAndEndPoints() - { - if (useCustomStartEnd) - { - startPoint = customStartPoint; - endPoint = customEndPoint; - } - else - { - // Generate multiple possible spawn points in the bottom third - for (int x = 1; x < gridWidth - 1; x++) - { - for (int y = 1; y < gridHeight / 3; y++) - { - possibleSpawnPoints.Add(new Vector2Int(x, y)); - } - } - - // Generate multiple possible exit points in the top third - for (int x = 1; x < gridWidth - 1; x++) - { - for (int y = (gridHeight * 2) / 3; y < gridHeight - 1; y++) - { - possibleExitPoints.Add(new Vector2Int(x, y)); - } - } - - // Pick random points from the possible locations - startPoint = possibleSpawnPoints[UnityEngine.Random.Range(0, possibleSpawnPoints.Count)]; - endPoint = possibleExitPoints[UnityEngine.Random.Range(0, possibleExitPoints.Count)]; - } - } - - private bool IsBorderPosition(Vector2Int pos) - { - return pos.x == 0 || pos.x == gridWidth - 1 || - pos.y == 0 || pos.y == gridHeight - 1; - } - - private Vector2Int GetNextPathPoint(Vector2Int current, Vector2Int target) - { - // Calculate direction to target - Vector2Int direction = target - current; - float distance = direction.magnitude; - - // List of possible next points - List possibleMoves = new List(); - - // Always try to move closer to the target when possible - if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y)) - { - // Prioritize horizontal movement - if (direction.x > 0) - possibleMoves.Add(current + Vector2Int.right); - else - possibleMoves.Add(current + Vector2Int.left); - } - else - { - // Prioritize vertical movement - if (direction.y > 0) - possibleMoves.Add(current + Vector2Int.up); - else - possibleMoves.Add(current + Vector2Int.down); - } - - // Add some randomness to prevent straight lines - if (UnityEngine.Random.value < 0.4f) - { - if (current.x > 1) - possibleMoves.Add(current + Vector2Int.left); - if (current.x < gridWidth - 2) - possibleMoves.Add(current + Vector2Int.right); - } - - // Filter out invalid moves - possibleMoves.RemoveAll(move => - IsOutOfBounds(move) || - mainPath.Contains(move) || - IsBorderPosition(move) - ); - - // If no valid moves, try moving directly towards target - if (possibleMoves.Count == 0) - { - Vector2Int directMove = current + new Vector2Int( - Mathf.Clamp(direction.x, -1, 1), - Mathf.Clamp(direction.y, -1, 1) - ); - - if (!IsOutOfBounds(directMove) && - !mainPath.Contains(directMove) && - !IsBorderPosition(directMove)) - { - return directMove; } } - - // Return random valid move, or current position if no valid moves - return possibleMoves.Count > 0 ? - possibleMoves[UnityEngine.Random.Range(0, possibleMoves.Count)] : - current; } + + // Add this to help with spawning public Vector2Int GetRandomSpawnPoint() { @@ -278,26 +266,66 @@ public class WFCGenerator : MonoBehaviour } } - void InitializeGrid(List allPrefabs) + private async void InitializeGrid() { grid = new WaveCell[gridWidth, gridHeight]; + var allPrefabs = chunkCompatibilityMatrix.prefabs; + + // First pass: Initialize all cells for (int x = 0; x < gridWidth; x++) { for (int y = 0; y < gridHeight; y++) { - // Start with all prefabs as possibilities - List possiblePrefabs = new List(allPrefabs); + Vector2Int pos = new Vector2Int(x, y); - // If using closed borders, restrict edge cells to prefabs with closed sockets - if (closedBorders) + if (mainPath.Contains(pos)) { - possiblePrefabs = FilterPrefabsForBorders(x, y, possiblePrefabs); + // Filter for floor-based prefabs + var pathPrefabs = allPrefabs.Where(prefab => + { + var conn = prefab.GetComponent(); + return !conn.IsBorderPrefab() && HasFloorConnection(conn); + }).ToList(); + + grid[x, y] = new WaveCell(pathPrefabs, pos); + } + else + { + List possiblePrefabs = new List(allPrefabs); + if (closedBorders) + { + possiblePrefabs = FilterPrefabsForBorders(x, y, possiblePrefabs); + } + grid[x, y] = new WaveCell(possiblePrefabs, pos); } - // Start with all prefabs as possibilities - grid[x, y] = new WaveCell(new List(possiblePrefabs), new Vector2Int(x, y)); + await Task.Delay(delayAwait); } } + + // Second pass: Collapse path cells + foreach (var pathPos in mainPath) + { + var cell = grid[pathPos.x, pathPos.y]; + cell.IsCollapsed = true; + cell.PossiblePrefabs = new List { + GetWeightedRandomPrefab(cell.PossiblePrefabs) + }; + InstantiateCollapsedCell(cell); + await Task.Delay(delayAwait); + } + + gridReady = true; + + StartCoroutine(RunWFC()); + } + + private bool HasFloorConnection(ChunkConnectionData conn) + { + return conn.NorthConnection == ConnectionSocket.floor && + conn.SouthConnection == ConnectionSocket.floor && + conn.EastConnection == ConnectionSocket.floor && + conn.WestConnection == ConnectionSocket.floor; } /* void OnDrawGizmos() @@ -327,7 +355,7 @@ public class WFCGenerator : MonoBehaviour }*/ - + // Restrict edge cells to prefabs with walls or closed connections List FilterPrefabsForBorders(int x, int y, List possiblePrefabs) @@ -428,35 +456,35 @@ public class WFCGenerator : MonoBehaviour PropagateConstraints(cellPos); } - /* // Find the cell with the smallest number of possible prefabs - Vector2Int FindMinEntropyCell() - { - int minEntropy = int.MaxValue; - List candidates = new List(); + /* // Find the cell with the smallest number of possible prefabs + Vector2Int FindMinEntropyCell() + { + int minEntropy = int.MaxValue; + List candidates = new List(); - for (int x = 0; x < gridWidth; x++) - { - for (int y = 0; y < gridHeight; y++) - { - WaveCell cell = grid[x, y]; - if (cell.IsCollapsed) continue; + for (int x = 0; x < gridWidth; x++) + { + for (int y = 0; y < gridHeight; y++) + { + WaveCell cell = grid[x, y]; + if (cell.IsCollapsed) continue; - if (cell.Entropy < minEntropy) - { - minEntropy = cell.Entropy; - candidates.Clear(); - candidates.Add(new Vector2Int(x, y)); - } - else if (cell.Entropy == minEntropy) - { - candidates.Add(new Vector2Int(x, y)); - } - } - } + if (cell.Entropy < minEntropy) + { + minEntropy = cell.Entropy; + candidates.Clear(); + candidates.Add(new Vector2Int(x, y)); + } + else if (cell.Entropy == minEntropy) + { + candidates.Add(new Vector2Int(x, y)); + } + } + } - // Pick a random candidate to avoid directional bias - return candidates[UnityEngine.Random.Range(0, candidates.Count)]; - }*/ + // Pick a random candidate to avoid directional bias + return candidates[UnityEngine.Random.Range(0, candidates.Count)]; + }*/ Vector2Int FindMinEntropyCell() { int minEntropy = int.MaxValue; @@ -520,31 +548,40 @@ public class WFCGenerator : MonoBehaviour async void CollapseCell(Vector2Int cellPos) { - await Task.Delay(delayAwait); // Simulating async work + await Task.Delay(delayAwait); WaveCell cell = grid[cellPos.x, cellPos.y]; if (cell.IsCollapsed || cell.Entropy == 0) return; - GameObject chosenPrefab = GetWeightedRandomPrefab(cell.PossiblePrefabs); - //Debug.Log("cell.PossiblePrefabs.count" + cell.PossiblePrefabs.Count); - //GameObject chosenPrefab = cell.PossiblePrefabs.Find(p => p.name.Contains("Floor")); - - if (chosenPrefab == null) + if (mainPath.Contains(cellPos)) { - Debug.LogError("No valid floor prefab found!"); + cell.PossiblePrefabs = cell.PossiblePrefabs.Where(prefab => + { + var conn = prefab.GetComponent(); + return !conn.IsBorderPrefab() && + conn.NorthConnection == ConnectionSocket.floor && + conn.SouthConnection == ConnectionSocket.floor && + conn.EastConnection == ConnectionSocket.floor && + conn.WestConnection == ConnectionSocket.floor; + }).ToList(); + + if (cell.PossiblePrefabs.Count == 0) + { + Debug.LogError($"No valid floor prefabs available for path at {cellPos}!"); + return; + } } - //Debug.Log("Collapsed cell: " + cellPos.x + ", " + cellPos.y + " = " + chosenPrefab.name); - // Collapse the cell to this prefab + GameObject chosenPrefab = GetWeightedRandomPrefab(cell.PossiblePrefabs); + cell.PossiblePrefabs = new List { chosenPrefab }; cell.IsCollapsed = true; InstantiateCollapsedCell(cell); - await Task.Delay(delayAwait); // Simulating async work + await Task.Delay(delayAwait); - // Propagate constraints to neighbors PropagateConstraints(cellPos); } @@ -583,7 +620,7 @@ public class WFCGenerator : MonoBehaviour return possiblePrefabs[0]; } - async void PropagateConstraints(Vector2Int startCellPos) + async void PropagateConstraints(Vector2Int startCellPos) { Queue cellsToProcess = new Queue(); cellsToProcess.Enqueue(startCellPos); @@ -593,6 +630,20 @@ public class WFCGenerator : MonoBehaviour Vector2Int cellPos = cellsToProcess.Dequeue(); WaveCell cell = grid[cellPos.x, cellPos.y]; + if (mainPath.Contains(cellPos)) + { + // Ensure we maintain floor connections for path tiles + cell.PossiblePrefabs = cell.PossiblePrefabs.Where(prefab => + { + var conn = prefab.GetComponent(); + return !conn.IsBorderPrefab() && + conn.NorthConnection == ConnectionSocket.floor && + conn.SouthConnection == ConnectionSocket.floor && + conn.EastConnection == ConnectionSocket.floor && + conn.WestConnection == ConnectionSocket.floor; + }).ToList(); + } + foreach (Direction dir in Enum.GetValues(typeof(Direction))) { Vector2Int neighborPos = GetNeighborPosition(cellPos, dir); @@ -608,7 +659,7 @@ public class WFCGenerator : MonoBehaviour for (int i = 0; i < validPrefabs.Count; i++) { - Debug.Log("Cell: " + cell.GridPosition + " has possible neighbors " + dir + " = " + validPrefabs[i].name); + //Debug.Log("Cell: " + cell.GridPosition + " has possible neighbors " + dir + " = " + validPrefabs[i].name); } // Check for contradictions here! @@ -627,7 +678,7 @@ public class WFCGenerator : MonoBehaviour cellsToProcess.Enqueue(neighborPos); } - + } await Task.Delay(delayAwait); // Simulating async work @@ -768,7 +819,7 @@ public class WFCGenerator : MonoBehaviour } - IEnumerator RunWFC() + private IEnumerator RunWFC() { while (!AllCellsCollapsed()) { @@ -776,8 +827,6 @@ public class WFCGenerator : MonoBehaviour CollapseCell(cellPos); yield return new WaitForSeconds(delayCoroutine); } - //if (AllCellsCollapsed()) - // InstantiatePrefabs(); } bool AllCellsCollapsed()