示例#1
0
        public static void ResizeLevel(int width, int height, ref LevelConfig config)
        {
            var resizedLayout = new GridNodeLayout[width * height];

            var defaultGridItem = GameConfig.GetDefaultLayoutGridItem(config.category);
            var openNode        = GameConfig.AllGridNodes.First(node => node.IsOpen);

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (config.IsInBounds(x, y))
                    {
                        resizedLayout[GetLinearIndex(x, y, width)] = config.GetNodeLayout(x, y);
                    }
                    else
                    {
                        resizedLayout[GetLinearIndex(x, y, width)] = new GridNodeLayout()
                        {
                            nodeId = openNode.ID, itemId = defaultGridItem.ID
                        }
                    };
                }
            }

            config.width  = width;
            config.height = height;
            config.layout = resizedLayout;
        }
示例#2
0
        public static void ExportLevelFile(int levelIndex, LevelConfig config)
        {
            string resourceName = GetLevelResourceName(levelIndex);

#if UNITY_EDITOR
            // the editor exports to Resources
            string pathToAsset = Path.Combine("Data", "Resources", $"{resourceName}.txt");
            string pathToFile  = Path.Combine(Application.dataPath, pathToAsset);
#else
            // device exports to persistent data, so the file can be retrieved later and imported into the Unity project
            string pathToFile = Path.Combine(Application.persistentDataPath, $"{resourceName}.txt");
#endif

            try
            {
                string json = JsonUtility.ToJson(config);
                Logger.LogEditor($"[EXPORT] Level={levelIndex}, Data={json}");                  // adb logcat, copy and paste ;)

                using (var writer = new StreamWriter(pathToFile))
                {
                    writer.Write(json);
                    Logger.LogEditor($"[EXPORT] Level '{resourceName}' was exported to file: {pathToFile}");
                }
            }
            catch (System.Exception e)
            {
                Logger.LogError($"Error while exporting '{resourceName}' to PersistentDataPath '{pathToFile}': {e.Message}");
            }

#if UNITY_EDITOR
            // reimport, else the imported asset is stale
            UnityEditor.AssetDatabase.ImportAsset(Path.Combine("Assets", pathToAsset));
#endif
        }
示例#3
0
        private void LoadLevel(Level.LoadLevelEvent loadLevelEvent)
        {
            _levelIndex  = loadLevelEvent.LevelIndex;
            _levelConfig = loadLevelEvent.LevelConfig;

            Logger.LogEditor($"Load level={_levelIndex}, size={_levelConfig.width}x{_levelConfig.height}");

            _levelScoreView.SetGoals(_levelIndex, _levelConfig);

            // clear the playfield
            ClearGridNodeInstances();
            ClearGridItemInstances();

            // if there is no grid state then auto-open the level editor
            if (loadLevelEvent.InitialGridState == null)
            {
                MessagePopup.ShowMessage("This level is empty. Edit mode is enabled.");
                _levelConfig = LevelConfig.CreateDefaultLevel(5, 5);
                EnableEditMode();
                return;
            }

            // calculate the playfield dimensions
            Vector3 playfieldSize = _playfieldTransform.sizeDelta;

            _tileSize        = CalculateTileSize(playfieldSize, new Vector2(_levelConfig.width, _levelConfig.height));
            _playfieldOrigin = new Vector3(             // [0,0] = lower-left corner
                (_levelConfig.width - 1) * _tileSize * -0.5f,
                (_levelConfig.height - 1) * _tileSize * -0.5f);

            // instantiate the level layout
            for (int y = 0; y < _levelConfig.height; y++)
            {
                for (int x = 0; x < _levelConfig.width; x++)
                {
                    var nodeLayout = _levelConfig.GetNodeLayout(x, y);

                    Assert.IsNotNull(nodeLayout.nodeId, $"Level layout is corrupted at ({x},{y})");

                    var pos = CalculateGridNodePosition(x, y);

                    // load the node from the config
                    CreateGridNodeView(x, y, nodeLayout.nodeId, pos);

                    // if in edit mode then load the item from the config, else load from the state
                    string itemType = _state == State.EditMode ?
                                      nodeLayout.itemId :
                                      loadLevelEvent.InitialGridState.FirstOrDefault(item => item.Index.x == x && item.Index.y == y)?.ItemId;

                    // if (itemType != null)	// HACK: load all items, even if they are invalid. this makes the level editor easier to use
                    {
                        CreateGridItemView(x, y, itemType, pos);
                    }
                }
            }
        }
示例#4
0
            public LoadLevelEvent(int levelIndex, LevelConfig levelConfig, GridNodeState[,] gridState)
            {
                // Payload.SetField((int)Fields.LevelIndex, levelIndex);

                LevelIndex  = levelIndex;
                LevelConfig = levelConfig;

                if (gridState != null)
                {
                    InitialGridState = new List <GridNodeState>();
                    foreach (var item in gridState)
                    {
                        InitialGridState.Add(item);
                    }
                }
            }
示例#5
0
        public void SetGoals(int levelIndex, LevelConfig levelConfig)
        {
            _levelConfig = levelConfig;

            // TODO: support other goal and challenge types

            //var sliderSize = _sliderTransform.sizeDelta;
            var sliderSize = _sliderTransform.rect;

            _goal1Transform.anchoredPosition = new Vector2(sliderSize.width * ((float)levelConfig.goal1 / (float)levelConfig.goal3) + _goalCompletedOffset, _goal1Transform.anchoredPosition.y);
            _goal2Transform.anchoredPosition = new Vector2(sliderSize.width * ((float)levelConfig.goal2 / (float)levelConfig.goal3) + _goalCompletedOffset, _goal2Transform.anchoredPosition.y);

            _slider.value    = 0;
            _pointsText.text = "0";
            _movesText.text  = levelConfig.challengeValue.ToString();
            _levelText.text  = levelIndex.ToString();
        }
示例#6
0
        public static void ExecuteCommand(Command command)
        {
            switch (command.CommandType)
            {
            case CommandType.LoadLevel:
            {
                int levelIndex = (command as LoadLevelCommand).LevelIndex;
                LevelConfig.LoadAsync(levelIndex, (index, config) =>
                    {
                        // TODO: continue loading even if the config is null. this would normally be an error, but we use this to trigger the level editor.
                        if (config == null)
                        {
                            config = new LevelConfig();
                        }

                        _levelState = new LevelState(index, config);
                        BroadcastEvent(new LoadLevelEvent(index, config, _levelState.Grid));
                    });
            } break;

            case CommandType.SubmitMatch:
            {
                var matchEvents = _levelState.TryMatchItems((command as SubmitMatchCommand)?.SelectedItems);

                BroadcastEvents(matchEvents);
            } break;

            case CommandType.ShuffleGrid:
            {
                var swappedEvent = _levelState.ShuffleGridItems();

                BroadcastEvent(swappedEvent);
            } break;

            case CommandType.Debug_Win:
            {
                BroadcastEvent(_levelState.Debug_WinLevel());
            } break;

            case CommandType.Debug_Lose:
            {
                BroadcastEvent(_levelState.Debug_LoseLevel());
            } break;
            }
        }
示例#7
0
        public void OnClick_EditMode_Resize()
        {
            if (!int.TryParse(_editModeInputWidth.text, out var width))
            {
                return;
            }

            if (!int.TryParse(_editModeInputHeight.text, out var height))
            {
                return;
            }

            LevelConfig.ResizeLevel(width, height, ref _levelConfig);
            LevelConfig.ExportLevelFile(_levelIndex, _levelConfig);

            // reload the level
            Level.ExecuteCommand(new Level.LoadLevelCommand(_levelIndex));
        }
示例#8
0
        public static LevelConfig CreateDefaultLevel(int width, int height)
        {
            string defaultCategory  = GameConfig.GetAllGridItemCategories().First();
            var    defaultMatchRule = GameConfig.AllMatchRules.First(rule => rule.Category == defaultCategory && rule.IsDefault);

            var config = new LevelConfig
            {
                width          = width,
                height         = height,
                layout         = new GridNodeLayout[width * height],
                category       = defaultCategory,
                excludeItemIds = new string[] {},
                matchRules     = defaultMatchRule.ID,
                goalType       = LevelGoalType.Points,
                goalItemId     = null,
                goal1          = 3000,
                goal2          = 7000,
                goal3          = 10000,
                challengeType  = LevelChallengeType.Moves,
                challengeValue = 10
            };

            var defaultGridItem = GameConfig.GetDefaultLayoutGridItem(config.category);
            var openNode        = GameConfig.AllGridNodes.First(node => node.IsOpen);

            for (int y = 0; y < config.height; y++)
            {
                for (int x = 0; x < config.width; x++)
                {
                    config.SetNodeLayout(x, y, new GridNodeLayout()
                    {
                        nodeId = openNode.ID, itemId = defaultGridItem.ID
                    });
                }
            }

            return(config);
        }
示例#9
0
        public LevelState(int levelIndex, LevelConfig config)
        {
            LevelIndex = levelIndex;
            Config     = config;
            Grid       = null;

            var includedItems = GameConfig.GetAllGridItemsInCategory(config.category, config.excludeItemIds);

            GridItemDrops = new GridItemDropDistribution(config.category, includedItems);

            if (config.width > 0 && config.height > 0)
            {
                var defaultGridItem = GameConfig.GetDefaultLayoutGridItem(config.category);

                // initialize the grid
                Grid = new GridNodeState[config.width, config.height];
                for (int y = 0; y < config.height; y++)
                {
                    for (int x = 0; x < config.width; x++)
                    {
                        var    layout = config.GetNodeLayout(x, y);
                        string itemId = null;
                        if (!string.IsNullOrEmpty(layout.itemId))
                        {
                            if (layout.itemId != defaultGridItem.ID)
                            {
                                itemId = layout.itemId;
                            }
                            else
                            {
                                itemId = GridItemDrops.Next();
                            }
                        }
                        Grid[x, y] = new GridNodeState(x, y, layout.nodeId, itemId);
                    }
                }
            }
        }
示例#10
0
        public void ShowScore(Level.LevelWinEvent winEvent, LevelConfig levelConfig)
        {
            _numStars       = winEvent.Stars;
            _scoreText.text = $"{winEvent.Points:n0}";
            _movesText.text = $"{winEvent.Moves}";
            _bestScore.SetActive(winEvent.Points >= winEvent.BestPoints);
            _bestMoves.SetActive(winEvent.Moves < winEvent.BestMoves || (winEvent.Moves == winEvent.BestMoves && winEvent.Moves < levelConfig.challengeValue));

            _starsAnimator.SetInteger(StarsInteger, winEvent.Stars);

            if (winEvent.Stars == 1)
            {
                _winText.text = "NO MOVES LEFT!";
            }
            else if (winEvent.Stars == 2)
            {
                _winText.text = "AMAZING!";
            }
            else
            {
                _winText.text = "YOU WIN!";
            }
        }
示例#11
0
        public void OnClick_EditMode_Save()
        {
            if (!GameConfig.AllMatchRules.Any(rule => rule.ID == _editModeTextMatchRules.text))
            {
                MessagePopup.ShowMessage($"Invalid Match Rules: '{_editModeTextMatchRules.text}'");
                return;
            }

            var allCategories = GameConfig.GetAllGridItemCategories();

            if (!allCategories.Contains(_editModeTextCategory.text))
            {
                MessagePopup.ShowMessage($"Invalid Category: '{_editModeTextCategory.text}'");
                return;
            }

            if (!int.TryParse(_editModeInputMaxItemTypes.text, out var maxItemTypes))
            {
                MessagePopup.ShowMessage($"Invalid Max Item Types: '{_editModeInputMaxItemTypes.text}'");
                return;
            }

            if (!Enum.TryParse(_editModeTextGoalType.text, out LevelGoalType goalType))
            {
                MessagePopup.ShowMessage($"Invalid Goal Type: '{_editModeTextGoalType.text}'");
                return;
            }

            string goalItemId = null;

            if (!string.IsNullOrEmpty(_editModeInputGoalItem.text))
            {
                goalItemId = _editModeInputGoalItem.text;
                if (GameConfig.GetGridItem(goalItemId).ID == null)
                {
                    MessagePopup.ShowMessage($"Invalid Goal Item ID: '{_editModeInputGoalItem.text}'");
                    return;
                }
            }

            if (!int.TryParse(_editModeInputGoal1.text, out var goal1))
            {
                MessagePopup.ShowMessage($"Invalid Goal #1: '{_editModeInputGoal1.text}'");
                return;
            }

            if (!int.TryParse(_editModeInputGoal2.text, out var goal2))
            {
                MessagePopup.ShowMessage($"Invalid Goal #2: '{_editModeInputGoal2.text}'");
                return;
            }

            if (!int.TryParse(_editModeInputGoal3.text, out var goal3))
            {
                MessagePopup.ShowMessage($"Invalid Goal #3: '{_editModeInputGoal3.text}'");
                return;
            }

            if (!Enum.TryParse(_editModeTextChallengeType.text, out LevelChallengeType challengeType))
            {
                MessagePopup.ShowMessage($"Invalid Challenge Type: '{_editModeTextChallengeType.text}'");
                return;
            }

            if (!int.TryParse(_editModeInputChallengeValue.text, out var moves) || moves < 1)
            {
                MessagePopup.ShowMessage($"Invalid Max Moves: '{_editModeInputChallengeValue.text}'");
                return;
            }

            _levelConfig.category       = _editModeTextCategory.text;
            _levelConfig.excludeItemIds = EditMode_ConvertMaxItemTypesToExcludedItemIds(_editModeTextCategory.text, Mathf.Max(0, maxItemTypes));
            _levelConfig.matchRules     = _editModeTextMatchRules.text;
            _levelConfig.goalType       = goalType;
            _levelConfig.goalItemId     = goalItemId;
            _levelConfig.goal1          = Mathf.Max(0, goal1);
            _levelConfig.goal2          = Mathf.Max(0, goal2);
            _levelConfig.goal3          = Mathf.Max(0, goal3);
            _levelConfig.challengeType  = challengeType;
            _levelConfig.challengeValue = moves;

            foreach (var gridNode in _gridNodeInstances)
            {
                var gridItem   = TryGetGridItem(gridNode.Index);
                var nodeLayout = _levelConfig.GetNodeLayout(gridNode.Index);
                nodeLayout.nodeId = gridNode.ID;
                nodeLayout.itemId = (gridItem != null && gridNode.GridNodeConfig.IsOpen) ? gridItem.ID : null;
                _levelConfig.SetNodeLayout(gridNode.Index, nodeLayout);
            }

            LevelConfig.ExportLevelFile(_levelIndex, _levelConfig);
        }