예제 #1
0
        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;
            }
        }
예제 #2
0
        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;
        }
예제 #3
0
        /// <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";
            }
        }
예제 #4
0
 public static bool IsInNavArea(this Vector3 pos)
 {
     return(LevelNavigation.tryGetNavigation(pos, out _));
 }
예제 #5
0
        /// <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();
        }