Forum begins after the advertisement:


[Part 27] Missing adjustments in “GameManager.cs”

Home Forums Video Game Tutorial Series Creating a Rogue-like Shoot-em Up in Unity [Part 27] Missing adjustments in “GameManager.cs”

Viewing 14 posts - 1 through 14 (of 14 total)
  • Author
    Posts
  • #18639
    Grim Rubbish
    Level 24
    Silver Supporter (Patron)
    Helpful?
    Up
    0
    ::

    In the “UITreasureChest.cs” at line 105 there is a reference to the GameManger.cs, but the GameState “TreasureChest” is missing.

    GameManager.instance.ChangeState(GameManager.GameState.TreasureChest);

    The Question is what has to be added in the GameManger.cs, is this enough?

    public enum GameState
    {
        Gameplay,
        Paused,
        GameOver,
        Success,
        LevelUp,
        TreasureChest
    }
    #18640
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::

    Yup, it is. Thank you so much for highlighting this Grim.

    #18648
    Grim Rubbish
    Level 24
    Silver Supporter (Patron)
    Helpful?
    Up
    0
    ::

    The problem seems not to be fixed! Whenever I enter a treasure chest the game won’t pause, the Treasure Chest button “open” isn’t clickable and I get multiple Debug errors claiming “STATE DOES NOT EXIST”. I guess we still have to define the State “TreasureChest” in the GameManager.cs, right?

    #18649
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::

    Can you share your GameManager script here?

    #18654
    Alp Apustaja
    Level 10
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    It looks like you’ve already added the TreasureChest state to your GameState enum, which is a good first step. However, it’s also important to ensure that the state is properly handled in the GameManager class. Here are a few steps you might need to take to fully implement this state:

    1. Implement State Change Logic: Ensure that you have logic in your GameManager class to handle what happens when the TreasureChest state is entered. This might involve pausing the game and showing the treasure chest UI.

      Example:

      public void ChangeState(GameState newState)
      {
          // Handle exiting the current state if needed
          switch (currentState)
          {
              case GameState.Gameplay:
                  // Logic to exit Gameplay state
                  break;
              case GameState.TreasureChest:
                  // Logic to exit TreasureChest state
                  break;
              // Handle other states
          }
      
          currentState = newState;
      
          // Handle entering the new state
          switch (newState)
          {
              case GameState.Gameplay:
                  // Logic to enter Gameplay state
                  break;
              case GameState.TreasureChest:
                  // Logic to enter TreasureChest state
                  PauseGame(); // Example of pausing the game
                  ShowTreasureChestUI(); // Show the UI for the treasure chest
                  break;
              // Handle other states
          }
      }
    2. Pause Game Logic: If the game is not pausing when you enter the TreasureChest state, make sure that the PauseGame() method (or whatever you are using) is correctly implemented.

    3. UI Interaction: Ensure that the UI elements related to the treasure chest are enabled and properly set up. If the button isn’t clickable, check if it is being disabled somewhere in your code or if there are any graphical layers blocking it.

    4. Debugging State Errors: If you are getting errors claiming “STATE DOES NOT EXIST”, double-check that you are referencing the state correctly throughout your code. Also, look for any places where you might be trying to access a state that hasn’t been fully implemented.

    5. Testing: Finally, you can add debug logs in your ChangeState method to see the flow of state changes, which can help identify where things might be going wrong.

    Here’s an example of adding debug logs:

    public void ChangeState(GameState newState)
    {
        Debug.Log($"Changing state from {currentState} to {newState}");
    
        // ... rest of your state change logic
    }

    By following these steps, you should be able to ensure that the TreasureChest state is implemented correctly and that the game behaves as expected when entering this state. If you continue to face issues, please provide more details about your GameManager implementation, and I can help further!

    #18656
    Grim Rubbish
    Level 24
    Silver Supporter (Patron)
    Helpful?
    Up
    0
    ::

    I think the problem is, that there should be a definition of what to do when “GameState.TreasureChest” is active. At the moment nothing is defined here:

    switch (currentState)
    {
        case GameState.Gameplay:
            // Code for the gameplay state
            CheckForPauseAndResume();
            UpdateStopwatch();
            CheckForBuffs();
            break;
        case GameState.Paused:
            // Code for the paused state
            CheckForPauseAndResume();
            break;
        case GameState.GameOver:
        case GameState.Success:
        case GameState.LevelUp:
        case GameState.TreasureChest:
            // Logic to enter TreasureChest state
            XXXXXXXX
            break;
        default:
            Debug.LogWarning("STATE DOES NOT EXIST");
            break;
    }
    #18657
    Alp Apustaja
    Level 10
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    Based on the reference information and the context provided, here’s a suggested implementation for the GameState.TreasureChest case:

    case GameState.TreasureChest:
        Time.timeScale = 0f; // Pause the game
        CheckForPauseAndResume(); // Allow potential resume functionality
        break;

    This implementation follows the pattern seen in other game states like Paused and GameOver, where:

    1. The game time is stopped using Time.timeScale = 0f
    2. The CheckForPauseAndResume() method is called to maintain consistent pause/resume behavior
    3. It prevents game logic from updating while in the treasure chest state
    #18658
    Grim Rubbish
    Level 24
    Silver Supporter (Patron)
    Helpful?
    Up
    0
    ::

    This is my current GameManager.cs (I only added “TreasureChest” in the public enum GameState. The question is, what should happen when the GameState “TreasureChest” is active? What about the “UITreasureChest.cs” in this GameState?

    using System.Collections;
    using UnityEngine;
    using UnityEngine.UI;
    using TMPro;
    public class GameManager : MonoBehaviour
    {
        public static GameManager instance;
    
        // Define the different states of the game
        public enum GameState
        {
            Gameplay,
            Paused,
            Craft,
            Shop,
            GameOver,
            Success,
            LevelUp,
            TreasureChest
        }
    
        // Store the current state of the game
        public GameState currentState;
    
        // Store the previous state of the game before it was paused
        public GameState previousState;
    
        [Header("Damage Text Settings")]
        public Canvas damageTextCanvas;
        public float textFontSize = 20;
        public TMP_FontAsset textFont;
        public Camera referenceCamera;
    
        public Image BossHealthBar;
    
        [Header("Screens")]
        public GameObject pauseScreen;
        public GameObject resultsScreen;
        public GameObject successScreen;
        public GameObject craftScreen;
        public GameObject shopScreen;
        public GameObject levelUpScreen;
        int stackedLevelUps = 0; // If we try to StartLevelUp() multiple times.
    
        [Header("Results Screen Displays")]
        public Image chosenCharacterImage;
        public Image chosenCharacterImagePause;
        public Image chosenCharacterImageCraft;
        public Image chosenCharacterImageShop;
        public Image chosenCharacterImageUpgrade;
        public TMP_Text chosenCharacterName;
        public TMP_Text chosenCharacterNamePause;
        public TMP_Text chosenCharacterNameCraft;
        public TMP_Text chosenCharacterNameShop;
        public TMP_Text chosenCharacterNameUpgrade;
        public TMP_Text levelReachedDisplay;
        public TMP_Text timeSurvivedDisplay;
    
    
        [Header("Stopwatch")]
        public float timeLimit; // The time limit in seconds
        float stopwatchTime; // The current time elapsed since the stopwatch started
        public TMP_Text stopwatchDisplay;
    
        [Header("Music")]
        public GameObject BackgroundMusic;
        public GameObject BackgroundMusicBoss;
        public GameObject DeathMusic;
        public GameObject EndMusic;
    
        [Header("Boss Health Bar and Message")]
        public GameObject bosshealthBar;
        public GameObject bosskilledInfo;
    
        [Header("Cheats and Log")]
        public GameObject cheatStuff;
    
        PlayerStats[] players; // Tracks all players.
    
        // Getters for parity with older scripts.
        public bool isGameOver { get { return currentState == GameState.Paused; } }
        public bool isSuccess { get { return currentState == GameState.Paused; } }
        public bool isShop { get { return currentState == GameState.Shop; } }
        public bool isCraft { get { return currentState == GameState.Craft; } }
        public bool choosingUpgrade { get { return currentState == GameState.LevelUp; } }
    
        // Gives us the time since the level has started.
        public float GetElapsedTime() { return stopwatchTime; }
    
        // Sums up the curse stat of all players and returns the value.
        public static float GetCumulativeCurse()
        {
            if (!instance) return 1;
    
            float totalCurse = 0;
            foreach (PlayerStats p in instance.players)
            {
                totalCurse += p.Actual.curse;
            }
            return Mathf.Max(1, totalCurse);
        }
    
        // Sum up the levels of all players and returns the value.
        public static int GetCumulativeLevels()
        {
            if (!instance) return 1;
    
            int totalLevel = 0;
            foreach (PlayerStats p in instance.players)
            {
                totalLevel += p.level;
            }
            return Mathf.Max(1, totalLevel);
        }
    
        void Awake()
        {
    
            players = FindObjectsOfType<PlayerStats>();
    
            //Warning check to see if there is another singleton of this kind already in the game
            if (instance == null)
            {
                instance = this;
            }
            else
            {
                Debug.LogWarning("EXTRA " + this + " DELETED");
                Destroy(gameObject);
            }
    
            DisableScreens();
        }
    
        void Update()
        {
            // Toggle Cheats on/off
            if (Input.GetKeyDown("0"))
            {
                cheatStuff.SetActive(!cheatStuff.activeInHierarchy);
            }
    
            switch (currentState)
            {
                case GameState.Gameplay:
                    // Code for the gameplay state
                    CheckForPauseAndResume();
                    UpdateStopwatch();
                    break;
                case GameState.Paused:
                    // Code for the paused state
                    CheckForPauseAndResume();
                    break;
                case GameState.GameOver:
                case GameState.Success:
                case GameState.Craft:
                case GameState.Shop:
                case GameState.LevelUp:
                    break;
                default:
                    Debug.LogWarning("STATE DOES NOT EXIST");
                    break;
            }
        }
        IEnumerator GenerateFloatingTextCoroutine(string text, Transform target, float duration = 1f, float speed = 100f)
        {
            // Start generating the floating text.
            GameObject textObj = new GameObject("Damage Floating Text");
            RectTransform rect = textObj.AddComponent<RectTransform>();
            TextMeshProUGUI tmPro = textObj.AddComponent<TextMeshProUGUI>();
            tmPro.text = text;
            tmPro.horizontalAlignment = HorizontalAlignmentOptions.Center;
            tmPro.verticalAlignment = VerticalAlignmentOptions.Middle;
            tmPro.fontSize = textFontSize;
            if (textFont) tmPro.font = textFont;
            rect.position = referenceCamera.WorldToScreenPoint(target.position);
    
            // Makes sure this is destroyed after the duration finishes.
            Destroy(textObj, duration);
    
            // Parent the generated text object to the canvas.
            textObj.transform.SetParent(instance.damageTextCanvas.transform);
            textObj.transform.SetSiblingIndex(0);
    
            // Pan the text upwards and fade it away over time.
            WaitForEndOfFrame w = new WaitForEndOfFrame();
            float t = 0;
            float yOffset = 0;
            Vector3 lastKnownPosition = target.position;
            while (t < duration)
            {
                // If the RectTransform is missing for whatever reason, end this loop.
                if (!rect) break;
    
                // Fade the text to the right alpha value.
                tmPro.color = new Color(tmPro.color.r, tmPro.color.g, tmPro.color.b, 1 - t / duration);
    
                // Update the enemy's position if it is still around.
                if (target) lastKnownPosition = target.position;
    
                // Pan the text upwards.
                yOffset += speed * Time.deltaTime;
                rect.position = referenceCamera.WorldToScreenPoint(lastKnownPosition + new Vector3(0, yOffset));
    
                // Wait for a frame and update the time.
                yield return w;
                t += Time.deltaTime; 
            }
        }
    
        public static void GenerateFloatingText(string text, Transform target, float duration = 1f, float speed = 1f)
        {
            // If the canvas is not set, end the function so we don't
            // generate any floating text.
            if (!instance.damageTextCanvas) return;
    
            // Find a relevant camera that we can use to convert the world
            // position to a screen position.
            if (!instance.referenceCamera) instance.referenceCamera = Camera.main;
    
            instance.StartCoroutine(instance.GenerateFloatingTextCoroutine(
                text, target, duration, speed
            ));
        }
    
        // Define the method to change the state of the game
        public void ChangeState(GameState newState)
        {
            previousState = currentState;
            currentState = newState;
        }
    
        //public GameObject otherobj;//your other object
        //public string scr;// your secound script name
    
        public void Shop()
        {
            if (currentState != GameState.Shop)
            {
                ChangeState(GameState.Shop);
                Time.timeScale = 0f; // Stop the game
                BackgroundMusic.SetActive(false);
                shopScreen.SetActive(true); // Enable the shop screen
                FindObjectOfType<ShowResources>().Show();
                FindObjectOfType<Shop>().ShopText();
                FindObjectOfType<Shop>().getShopItems();
                FindObjectOfType<PlayerStats>().showDamageStats();
            }
        }
    
        public void CloseShop()
        {
            if (currentState == GameState.Shop)
            {
                ChangeState(previousState);
                Time.timeScale = 1f; // Stop the game
                BackgroundMusic.SetActive(true);
                //(otherobj.GetComponent(scr) as MonoBehaviour).enabled = false;
                FindObjectOfType<ShowResources>().Hide();
                shopScreen.SetActive(false); // Disable the shop screen
    
            }
        }
    
       public void Craft()
        {
            if (currentState != GameState.Craft)
            {
                ChangeState(GameState.Craft);
                Time.timeScale = 0f; // Stop the game
                BackgroundMusic.SetActive(false);
                craftScreen.SetActive(true); // Enable the craft screen
                FindObjectOfType<Crafting>().getCraftItems();
                FindObjectOfType<ShowResources>().Show();
                FindObjectOfType<PlayerStats>().showDamageStats();
                //AudioListener.pause = true;
            }
    
        }
        public void CloseCraft()
        {
            if (currentState == GameState.Craft)
            {
                ChangeState(previousState);
                Time.timeScale = 1f; // Stop the game
                BackgroundMusic.SetActive(true);
                FindObjectOfType<ShowResources>().Hide();
                craftScreen.SetActive(false); // Disable the craft screen
                //AudioListener.pause = false;
            }
        } 
    
        public void PauseGame()
        {
            if (currentState != GameState.Paused)
            {
                ChangeState(GameState.Paused);
                Time.timeScale = 0f; // Stop the game
                pauseScreen.SetActive(true); // Enable the pause screen
                FindObjectOfType<ShowResources>().Show();
                FindObjectOfType<PlayerStats>().showDamageStats();
                AudioListener.pause = true;
            }
        }
        public void ResumeGame()
        {
            if (currentState == GameState.Paused)
            {
                ChangeState(previousState);
                Time.timeScale = 1f; // Resume the game
                pauseScreen.SetActive(false); //Disable the pause screen
                FindObjectOfType<ShowResources>().Hide();
                AudioListener.pause = false;
            }
        }
    
        // Define the method to check for pause and resume input
        void CheckForPauseAndResume()
        {
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                if (currentState == GameState.Paused)
                {
                    ResumeGame();
                }
                else
                {
                    PauseGame();
                }
            }
        }
    
        void DisableScreens()
        {
            pauseScreen.SetActive(false);
            resultsScreen.SetActive(false);
            successScreen.SetActive(false);
            shopScreen.SetActive(false);
            craftScreen.SetActive(false);
            levelUpScreen.SetActive(false);
        }
        public void GameOver()
        {
            timeSurvivedDisplay.text = stopwatchDisplay.text;
    
            // Set the Game Over variables here.
            ChangeState(GameState.GameOver);
            Time.timeScale = 0f; //Stop the game entirely
            DisplayResults();
            FindObjectOfType<ShowResources>().Show();
            BackgroundMusic.SetActive(false);
            BackgroundMusicBoss.SetActive(false);
            DeathMusic.SetActive(true);
        }
        public void Success()
        {
            StartCoroutine(SuccessEnding());
        }
        IEnumerator SuccessEnding()
        {
            timeSurvivedDisplay.text = stopwatchDisplay.text;
            bosshealthBar.SetActive(false);
            bosskilledInfo.SetActive(true);
            yield return new WaitForSeconds(5);
    
            // Set the Success variables here.
            ChangeState(GameState.Success);
            Time.timeScale = 0f; //Stop the game entirely
            DisplaySuccess();
            FindObjectOfType<ShowResources>().Show();
            BackgroundMusic.SetActive(false);
            BackgroundMusicBoss.SetActive(false);
            EndMusic.SetActive(true);
        }
    
        void DisplaySuccess()
        {
            successScreen.SetActive(true);
        }
        void DisplayResults()
        {
            resultsScreen.SetActive(true);
        }
    
        public void AssignChosenCharacterUI(CharacterData chosenCharacterData)
        {
            chosenCharacterImage.sprite = chosenCharacterImagePause.sprite = chosenCharacterImageShop.sprite = chosenCharacterImageCraft.sprite = chosenCharacterImageUpgrade.sprite = chosenCharacterData.Icon;
            chosenCharacterName.text = chosenCharacterNamePause.text = chosenCharacterNameShop.text = chosenCharacterNameCraft.text = chosenCharacterNameUpgrade.text = chosenCharacterData.FullName;
        }
    
        public void AssignLevelReachedUI(int levelReachedData)
        {
            levelReachedDisplay.text = levelReachedData.ToString();
        }
    
        void UpdateStopwatch()
        {
            stopwatchTime += Time.deltaTime;
            UpdateStopwatchDisplay();
    
            if (stopwatchTime >= timeLimit)
            {
                foreach (PlayerStats p in players)
                    p.SendMessage("GAME ENDS");
            }
        }
        void UpdateStopwatchDisplay()
        {
            // Calculate the number of minutes and seconds that have elapsed
            int minutes = Mathf.FloorToInt(stopwatchTime / 60);
            int seconds = Mathf.FloorToInt(stopwatchTime % 60);
    
            // Update the stopwatch text to display the elapsed time
            stopwatchDisplay.text = string.Format("{0:00}:{1:00}", minutes, seconds);
        }
        public void StartLevelUp()
        {
            ChangeState(GameState.LevelUp);
    
            // If the level up screen is already active, record it.
            if (levelUpScreen.activeSelf) stackedLevelUps++;
            else
            {
                levelUpScreen.SetActive(true);
                FindObjectOfType<ShowResources>().Show();
                Time.timeScale = 0f; //Pause the game for now
    
                foreach (PlayerStats p in players)
                    p.SendMessage("RemoveAndApplyUpgrades");
    
            }
        }
        public void EndLevelUp()
        {
            Time.timeScale = 1f;    //Resume the game
            levelUpScreen.SetActive(false);
            FindObjectOfType<ShowResources>().Hide();
            ChangeState(GameState.Gameplay);
            // Increase Insight +1
            FindObjectOfType<PlayerStats>().IncreaseInsight(1);
    
            if (stackedLevelUps > 0)
            {
                stackedLevelUps--;
                StartLevelUp();
            }
        }
    }
    #18659
    Alp Apustaja
    Level 10
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    Based on the existing pattern in the GameManager.cs, here’s how you should handle the TreasureChest state:

    1. In the Update() method, add a case for GameState.TreasureChest:
    case GameState.TreasureChest:
        CheckForPauseAndResume();
        break;
    1. Add a method similar to other state-specific methods like Shop() and Craft():
    public void OpenTreasureChest()
    {
        if (currentState != GameState.TreasureChest)
        {
            ChangeState(GameState.TreasureChest);
            Time.timeScale = 0f; // Stop the game
            // Activate treasure chest UI
            // You'll need to add a treasureChestScreen to your [Header("Screens")] section
            treasureChestScreen.SetActive(true);
            FindObjectOfType().Show();
        }
    }
    
    public void CloseTreasureChest()
    {
        if (currentState == GameState.TreasureChest)
        {
            ChangeState(previousState);
            Time.timeScale = 1f; // Resume the game
            treasureChestScreen.SetActive(false);
            FindObjectOfType().Hide();
        }
    }
    1. Update the DisableScreens() method to include the treasure chest screen:
    void DisableScreens()
    {
        // ... existing code ...
        treasureChestScreen.SetActive(false);
    }

    Would you like me to elaborate on any of these points or clarify anything about implementing the TreasureChest state?

    #18661
    Grim Rubbish
    Level 24
    Silver Supporter (Patron)
    Helpful?
    Up
    0
    ::

    @Terence This seems a little odd, can you confirm that these adjustments in the “GameManger.cs” are effective?

    #18663
    Alp Apustaja
    Level 10
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    The adjustments I suggested for handling the GameState.TreasureChest should indeed be effective if implemented correctly. To summarize and clarify:

    1. State Management: You added the TreasureChest case in the Update() method, which allows the game to check for pause and resume functionality while the treasure chest state is active.

    2. Open and Close Methods: The OpenTreasureChest() and CloseTreasureChest() methods will manage transitioning to and from the TreasureChest state. These methods ensure that:

      • When opening the treasure chest, the game pauses, and the treasure chest UI is shown.
      • When closing the treasure chest, it resumes the previous game state and hides the UI.
    3. Disable Screens: By updating the DisableScreens() method to include the treasure chest screen, you ensure that the UI is appropriately managed when switching states.

    Checklist for Effectiveness:

    • UI Activation: Ensure that you have a GameObject for the treasureChestScreen and that it’s referenced correctly in your GameManager.
    • Testing: After implementing these changes, test the following:
      • Entering a treasure chest pauses the game.
      • The treasure chest UI appears and is interactive.
      • Closing the treasure chest resumes the previous game state and hides the UI.

    Debugging:

    If you encounter any issues:

    • Add debug logs in the OpenTreasureChest() and CloseTreasureChest() methods to confirm they are being called.
    • Check for any errors in the console that may indicate issues with UI elements or state transitions.

    If everything is set up correctly, these adjustments should work effectively to manage the treasure chest state within your game. If you still run into issues, please let me know, and we can troubleshoot further!

    #18677
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::
    @Terence This seems a little odd, can you confirm that these adjustments in the “GameManger.cs” are effective?

    Grim, you’re right. You should only need the highlighted portion below after adding TreasureChest to the GameState enum:

    void Update()
    {
        switch (currentState)
        {
            case GameState.Gameplay:
                // Code for the gameplay state
                Time.timeScale = 1.0f;
                CheckForPauseAndResume();
                UpdateStopwatch();
                break;
            case GameState.Paused:
                // Code for the paused state
                CheckForPauseAndResume();
                break;
            case GameState.GameOver:
            case GameState.TreasureChest:
                Time.timeScale = 0;
                break;
            case GameState.LevelUp:
                break;
            default:
                Debug.LogWarning("STATE DOES NOT EXIST");
                break;
        }
    }

    It shares the same state logic as GameOver.

    #18679
    Grim Rubbish
    Level 24
    Silver Supporter (Patron)
    Helpful?
    Up
    2
    ::

    Thank you Terence, it worked!

    and 1 other person have upvoted this post.
    #18747
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::

    There were also a couple of changes to Part 27’s project files that were not documented:

    • Instead of having the Done button do the SaveCoinsToStash() (as we did in Part 26), we instead have the GameManager call it whenever GameOver() is triggered. This makes the action much easier to find, which makes debugging easier.
    • Since the game time and clock speed is now determined by the level data that we key into the level select scene, we’ve also added a default value for both game time and clock speed that the GameManager defaults to.
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using TMPro;
    
    public class GameManager : MonoBehaviour
    {
        public static GameManager instance;
    
        // Define the different states of the game
        public enum GameState
        {
            Gameplay,
            Paused,
            GameOver,
            LevelUp,
            TreasureChest
        }
    
        // Store the current state of the game
        public GameState currentState;
    
        // Store the previous state of the game before it was paused
        public GameState previousState;
    
        [Header("Damage Text Settings")]
        public Canvas damageTextCanvas;
        public float textFontSize = 20;
        public TMP_FontAsset textFont;
        public Camera referenceCamera;
    
        [Header("Screens")]
        public GameObject pauseScreen;
        public GameObject resultsScreen;
        public GameObject levelUpScreen;
        int stackedLevelUps = 0; // If we try to StartLevelUp() multiple times.
    
        [Header("Results Screen Displays")]
        public Image chosenCharacterImage;
        public TMP_Text chosenCharacterName;
        public TMP_Text levelReachedDisplay;
        public TMP_Text timeSurvivedDisplay;
    
        const float DEFAULT_TIME_LIMIT = 1800f;
        const float DEFAULT_CLOCK_SPEED = 1f;
        float ClockSpeed => UILevelSelector.currentLevel?.clockSpeed ?? DEFAULT_CLOCK_SPEED;
        float TimeLimit => UILevelSelector.currentLevel?.timeLimit ?? DEFAULT_TIME_LIMIT;
    
        [Header("Stopwatch")]
        public float timeLimit; // The time limit in seconds
        float stopwatchTime; // The current time elapsed since the stopwatch started
        public TMP_Text stopwatchDisplay;
    
        bool levelEnded = false; // Has the time limit been reached?
        public GameObject reaperPrefab; // Spawns after time limit has been reached;
    
        PlayerStats[] players; // Tracks all players.
    
        // Getters for parity with older scripts.
        public bool isGameOver { get { return currentState == GameState.Paused; } }
        public bool choosingUpgrade { get { return currentState == GameState.LevelUp; } }
    
        // Gives us the time since the level has started.
        public float GetElapsedTime() { return stopwatchTime; }
    
        // Sums up the curse stat of all players and returns the value.
        public static float GetCumulativeCurse()
        {
            if (!instance) return 1;
    
            float totalCurse = 0;
            foreach (PlayerStats p in instance.players)
            {
                totalCurse += p.Actual.curse;
            }
            return Mathf.Max(1, totalCurse);
        }
    
        // Sum up the levels of all players and returns the value.
        public static int GetCumulativeLevels()
        {
            if (!instance) return 1;
    
            int totalLevel = 0;
            foreach (PlayerStats p in instance.players)
            {
                totalLevel += p.level;
            }
            return Mathf.Max(1, totalLevel);
        }
    
        void Awake()
        {
            players = FindObjectsOfType<PlayerStats>();
    
            //Set the level's Time Limit
            timeLimit = UILevelSelector.currentLevel.timeLimitTimeLimit;
    
            //Warning check to see if there is another singleton of this kind already in the game
            if (instance == null)
            {
                instance = this;
            }
            else
            {
                Debug.LogWarning("EXTRA " + this + " DELETED");
                Destroy(gameObject);
            }
    
            DisableScreens();
        }
    
        void Update()
        {
            switch (currentState)
            {
                case GameState.Gameplay:
                    // Code for the gameplay state
                    Time.timeScale = 1;
                    CheckForPauseAndResume();
                    UpdateStopwatch();
                    break;
                case GameState.Paused:
                    // Code for the paused state
                    CheckForPauseAndResume();
                    break;
                case GameState.GameOver:
                case GameState.TreasureChest:
                    Time.timeScale = 0;
                    break;
                case GameState.LevelUp:
                    break;
                default:
                    Debug.LogWarning("STATE DOES NOT EXIST");
                    break;
            }
        }
    
        IEnumerator GenerateFloatingTextCoroutine(string text, Transform target, float duration = 1f, float speed = 50f)
        {
            // Start generating the floating text.
            GameObject textObj = new GameObject("Damage Floating Text");
            RectTransform rect = textObj.AddComponent<RectTransform>();
            TextMeshProUGUI tmPro = textObj.AddComponent<TextMeshProUGUI>();
            tmPro.text = text;
            tmPro.horizontalAlignment = HorizontalAlignmentOptions.Center;
            tmPro.verticalAlignment = VerticalAlignmentOptions.Middle;
            tmPro.fontSize = textFontSize;
            if (textFont) tmPro.font = textFont;
            rect.position = referenceCamera.WorldToScreenPoint(target.position);
    
            // Makes sure this is destroyed after the duration finishes.
            Destroy(textObj, duration);
    
            // Parent the generated text object to the canvas.
            textObj.transform.SetParent(instance.damageTextCanvas.transform);
            textObj.transform.SetSiblingIndex(0);
    
            // Pan the text upwards and fade it away over time.
            WaitForEndOfFrame w = new WaitForEndOfFrame();
            float t = 0;
            float yOffset = 0;
            Vector3 lastKnownPosition = target.position;
            while (t < duration)
            {
                // If the RectTransform is missing for whatever reason, end this loop.
                if (!rect) break;
    
                // Fade the text to the right alpha value.
                tmPro.color = new Color(tmPro.color.r, tmPro.color.g, tmPro.color.b, 1 - t / duration);
    
                // Update the enemy's position if it is still around.
                if (target) lastKnownPosition = target.position;
    
                // Pan the text upwards.
                yOffset += speed * Time.deltaTime;
                rect.position = referenceCamera.WorldToScreenPoint(lastKnownPosition + new Vector3(0, yOffset));
    
                // Wait for a frame and update the time.
                yield return w;
                t += Time.deltaTime;
            }
        }
    
        public static void GenerateFloatingText(string text, Transform target, float duration = 1f, float speed = 1f)
        {
            // If the canvas is not set, end the function so we don't
            // generate any floating text.
            if (!instance.damageTextCanvas) return;
    
            // Find a relevant camera that we can use to convert the world
            // position to a screen position.
            if (!instance.referenceCamera) instance.referenceCamera = Camera.main;
    
            instance.StartCoroutine(instance.GenerateFloatingTextCoroutine(
                text, target, duration, speed
            ));
        }
    
        // Define the method to change the state of the game
        public void ChangeState(GameState newState)
        {
            previousState = currentState;
            currentState = newState;
        }
    
        public void PauseGame()
        {
            if (currentState != GameState.Paused)
            {
                ChangeState(GameState.Paused);
                Time.timeScale = 0f; // Stop the game
                pauseScreen.SetActive(true); // Enable the pause screen
            }
        }
    
        public void ResumeGame()
        {
            if (currentState == GameState.Paused)
            {
                ChangeState(previousState);
                Time.timeScale = 1f; // Resume the game
                pauseScreen.SetActive(false); //Disable the pause screen
            }
        }
    
        // Define the method to check for pause and resume input
        void CheckForPauseAndResume()
        {
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                if (currentState == GameState.Paused)
                {
                    ResumeGame();
                }
                else
                {
                    PauseGame();
                }
            }
        }
    
        void DisableScreens()
        {
            pauseScreen.SetActive(false);
            resultsScreen.SetActive(false);
            levelUpScreen.SetActive(false);
        }
    
        public void GameOver()
        {
            timeSurvivedDisplay.text = stopwatchDisplay.text;
    
            // Set the Game Over variables here.
            ChangeState(GameState.GameOver);
            Time.timeScale = 0f; //Stop the game entirely
            DisplayResults();
    
            // Save all the coins of all the players to the save file.
            foreach (PlayerStats p in players)
            {
                p.GetComponentInChildren<PlayerCollector>().SaveCoinsToStash();
            }
    
            // Add all players' coins to their save file, since the game has ended.
            foreach(PlayerStats p in players)
            {
                if(p.TryGetComponent(out PlayerCollector c))
                {
                    c.SaveCoinsToStash();
                }
            }
        }
    
        void DisplayResults()
        {
            resultsScreen.SetActive(true);
        }
    
        public void AssignChosenCharacterUI(CharacterData chosenCharacterData)
        {
            chosenCharacterImage.sprite = chosenCharacterData.Icon;
            chosenCharacterName.text = chosenCharacterData.Name;
        }
    
        public void AssignLevelReachedUI(int levelReachedData)
        {
            levelReachedDisplay.text = levelReachedData.ToString();
        }
    
        public Vector2 GetRandomPlayerLocation()
        {
            int chosenPlayer = Random.Range(0, players.Length);
            return new Vector2(players[chosenPlayer].transform.position.x, players[chosenPlayer].transform.position.y);
        }
    
        void UpdateStopwatch()
        {
            stopwatchTime += Time.deltaTime * ClockSpeedUILevelSelector.currentLevel.clockSpeed;
            UpdateStopwatchDisplay();
    
            if (stopwatchTime >= timeLimit && !levelEnded)
            {
                levelEnded = true;
    
                // Set the enemy/event spawner GameObject inactive to stop enemies from spawning and kill the remaining enemies onscreen.
                FindObjectOfType<SpawnManager>().gameObject.SetActive(false);
                foreach (EnemyStats e in FindObjectsOfType<EnemyStats>())
                    e.SendMessage("Kill");
    
                // Spawn the Reaper off-camera
                Vector2 reaperOffset = Random.insideUnitCircle * 50f;
                Vector2 spawnPosition = GetRandomPlayerLocation() + reaperOffset;
                Instantiate(reaperPrefab, spawnPosition, Quaternion.identity);
    
    
            }
        }
    
        void UpdateStopwatchDisplay()
        {
            // Calculate the number of minutes and seconds that have elapsed
            int minutes = Mathf.FloorToInt(stopwatchTime / 60);
            int seconds = Mathf.FloorToInt(stopwatchTime % 60);
    
            // Update the stopwatch text to display the elapsed time
            stopwatchDisplay.text = string.Format("{0:00}:{1:00}", minutes, seconds);
        }
    
        public void StartLevelUp()
        {
            ChangeState(GameState.LevelUp);
    
            // If the level up screen is already active, record it.
            if (levelUpScreen.activeSelf) stackedLevelUps++;
            else
            {
                levelUpScreen.SetActive(true);
                Time.timeScale = 0f; //Pause the game for now
    
                foreach (PlayerStats p in players)
                    p.SendMessage("RemoveAndApplyUpgrades");
            }
        }
    
        public void EndLevelUp()
        {
            Time.timeScale = 1f;    //Resume the game
            levelUpScreen.SetActive(false);
            ChangeState(GameState.Gameplay);
    
            if (stackedLevelUps > 0)
            {
                stackedLevelUps--;
                StartLevelUp();
            }
        }
    }
Viewing 14 posts - 1 through 14 (of 14 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: