private IEnumerator GenerateLevel() { if (lvlWidth <= 0) { Debug.LogError($"Can't generate a level with {lvlWidth} width"); Status = LevelGenerationStatus.Abort; yield break; } if (lvlHeight <= 0) { Debug.LogError($"Can't generate a level with {lvlHeight} height"); Status = LevelGenerationStatus.Abort; yield break; } Status = LevelGenerationStatus.Idle; genProgressionPrev = -1; genProgression = 0; rnd = new System.Random(DateTime.Now.Millisecond); Debug.Log($"Generating level {lvlWidth}x{lvlHeight}"); newLevel = new GridXY <Element>(); newLevel.CreateGridXY(lvlWidth, lvlHeight, 1, Vector3.zero, false, Element.NULL, Element.NULL); LevelNavigation.SetUp(lvlWidth, lvlHeight, true, false); Status = LevelGenerationStatus.Generating; yield return(null); List <Vector2Int> nodes = new List <Vector2Int>(); Coroutine generatingNodes = StartCoroutine(GenerateNodes(Mathf.RoundToInt(Mathf.Clamp((lvlWidth * lvlHeight) * (nodesPercentage / 100f), 2, newLevel.Size)), (generatedNodes) => { nodes = generatedNodes; })); yield return(generatingNodes); yield return(null); int pathsNum = 0; Coroutine generatingPaths = StartCoroutine(GeneratePaths(nodes, (generatedPathsNum) => { pathsNum = generatedPathsNum; })); yield return(generatingPaths); yield return(null); if (pathsNum > 0) { Status = LevelGenerationStatus.Completed; } else { Status = LevelGenerationStatus.Abort; } }
private IEnumerator GeneratePaths(List <Vector2Int> nodes, Action <int> callback) { if (nodes.Count <= 0) { Debug.LogWarning("There are no nodes for which generate paths"); yield break; } int attempts = 0; int maxAttempts = nodes.Count * 2; List <LevelNavigation.PathNode> newPath = new List <LevelNavigation.PathNode>(); List <bool> nodesUsed = Enumerable.Repeat(false, nodes.Count).ToList(); int path = 0; int nodesUnusable = 0; Status = LevelGenerationStatus.Paths; yield return(null); for (path = 0; path + nodesUnusable + 1 < nodes.Count && attempts < maxAttempts; path++, attempts++) { newPath = LevelNavigation.FindPath(nodes[path], nodes[path + nodesUnusable + 1], newLevel); if (newPath == null) { path--; nodesUnusable += (path + nodesUnusable < nodes.Count - 2) ? 1 : 0; } else { ApplyPath(newPath); foreach (LevelNavigation.PathNode p in newPath.Where(tmpP => nodes.Contains(tmpP.GetCell())).ToList()) { nodesUsed[nodes.IndexOf(p.GetCell())] = true; } path += nodesUnusable; nodesUnusable = 0; } genProgression = Mathf.Max((float)path / nodes.Count, (float)attempts / maxAttempts); yield return(null); } Debug.Log($"Generated {path}/{nodes.Count - 1} paths in {attempts}/{maxAttempts} attempts"); nodes = RemoveUnusedNodes(nodes, nodesUsed); newLevel.SetTile(nodes[0], Element.Start); newLevel.SetTile(nodes[nodes.Count - 1], Element.End); callback?.Invoke(nodes.Count); yield break; }
/// <summary> /// Update the attached text to the distance between the specified cell and the level end. /// </summary> /// <param name="startX">Start cell X.</param> /// <param name="startY">Start cell Y.</param> public void UpdateValue(int startX, int startY) { if (text == null) { return; } if (!LevelNavigation.IsReady) { return; } List <LevelNavigation.PathNode> path = LevelNavigation.FindPath(new Vector2Int(startX, startY), LevelManager.Main.EndCell); if (path != null) { text.text = (path.Where(p => LevelManager.Main.Grid.GetTile(p.GetCell()).ToDirection() == Direction.All).ToList().Count - 1).ToString(); } else { text.text = "N/A"; } }
public static bool IsInNavArea(this Vector3 pos) { return(LevelNavigation.tryGetNavigation(pos, out _)); }
/// <summary> /// Load a new level /// </summary> /// <param name="newLevel">New level.</param> public void LoadLevel(GridXY <Element> newLevel) { if (newLevel == null || newLevel.Size == 0) { Debug.LogWarning("The new level grid is not valid"); return; } Debug.Log($"0. Loading level {newLevel.Width}x{newLevel.Height}..."); ClearLevel(); Debug.Log($"1. Initializing level..."); Grid.CreateGridXY(newLevel.Width, newLevel.Height, 1, Vector3.zero, true, Element.NULL, Element.NULL); Debug.Log("Level is not playable!"); LvlState = LevelState.NotPlayable; OnLevelNotPlayable?.Invoke(this, null); Debug.Log("2. Generating level..."); StartCell = Vector2Int.one * -1; EndCell = Vector2Int.one * -1; bool hasStart = false; bool hasEnd = Grid.Size == 1; Element type; for (int x = 0; x < Grid.Width; x++) { for (int y = 0; y < Grid.Height; y++) { type = newLevel.GetTile(x, y); if (showDebugLog) { Debug.Log($"Setted Tile {x},{y} ({type})"); } Grid.SetTile(x, y, type); if (type == Element.Start) { StartCell = new Vector2Int(x, y); hasStart = true; } else { if (type == Element.End) { EndCell = new Vector2Int(x, y); hasEnd = true; } } } } Debug.Log("Level is ready!"); LvlState = LevelState.Ready; OnLevelReady?.Invoke(this, new OnLevelReadyEventArgs { width = Grid.Width, height = Grid.Height }); if (!hasStart || !hasEnd) { Debug.LogWarning($"Level has {(!hasStart ? "NO": "")} Start and {(!hasEnd ? "NO" : "")} End"); return; } LevelNavigation.SetUp(Grid.Width, Grid.Height, false, true, Grid); Debug.Log("Level is playable!"); LvlState = LevelState.Playable; OnLevelPlayable?.Invoke(this, new OnLevelPlayableEventArgs { startX = StartCell.x, startY = StartCell.y, endX = EndCell.x, endY = EndCell.y }); OnLevelStart?.Invoke(); }