Forum begins after the advertisement:

 


Nulling values in GameManager after repeating a game

Home Forums Video Game Tutorial Series Creating a Rogue-like Shoot-em Up in Unity Nulling values in GameManager after repeating a game

Viewing 3 posts - 1 through 3 (of 3 total)
  • Author
    Posts
  • #18802
    Patryk
    Level 13
    Bronze Supporter (Patron)
    Helpful?
    Up
    1
    ::

    Greetings, I really enjoy your video series and it inspiered me to make my own version and incorporate map generation as an additional feature. I managed to prepare a system where player have to defeat the boss on a specific dungeon, find a key and then find a portal in order to enter another floor. I made new script explicitely for handling changing floor system. Unfortunetely during test much later that I should do I stumbled upon a problem where after repeating game when player die all variables recently assigned to the GameManager disapear and there is no way to play another time. Since I am a beginner at this I can’t find a possible explanation for this. Is it possible that LevelManager script somehow messes with functionality of a GameManager?

    //LevelManager.cs

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using RoomCoordinates;
    
    
    public class LevelManager : MonoBehaviour
    {
        [Header("UI")]
        [SerializeField] private PopupManager popupManager;
        public static LevelManager Instance { get; private set; }
    
        [Header("Level Settings")]
        public int currentLevel = 1;
        public int bossesKilled = 0;
        public int bossesRequiredForPortal = 1;
        public bool portalSpawned = false;
    
    
        [Header("Refereces")]
        public GameObject portalPrefab;
        public GameObject keyPrefab;
        public Transform player;
        public CAMapGenerator mapGenerator;
        public NewEnemySpawner enemySpawner;
        //public GameManager gameManager;
    
    
        [Header("Portal Spawn Settings")]
        public float minDistanceFromPlayer = 10f;
        public float minDistanceFromWalls = 3f;
    
        private float levelStartTime;
        private List<GameObject> currentEnemies = new List<GameObject>();
    
    
        private void Awake()
        {
            if (Instance == null)
            {
                Instance = this;
                DontDestroyOnLoad(gameObject);
            }
            else
            {
                Destroy(gameObject);
            }
        }
    
        private void Start()
        {
            levelStartTime = Time.time;
            FindReferences();
            StartCoroutine(CheckForPortalConditions());
        }
    
        void FindReferences()
        {
            if (player == null)
            {
                GameObject playerObj = GameObject.FindGameObjectWithTag("Player");
                if (playerObj != null)
                    player = playerObj.transform;
            }
            if (mapGenerator == null)
                mapGenerator = CAMapGenerator.Instance;
            if (enemySpawner == null)
                enemySpawner = FindAnyObjectByType<NewEnemySpawner>();
        }
    
    
        IEnumerator CheckForPortalConditions()
        {
            while (true)
            {
                yield return new WaitForSeconds(5f);
    
                if (portalSpawned)
                    continue;
                bool bossCondition = bossesKilled >= bossesRequiredForPortal;
    
                if (bossCondition) //lub albo i
                {
                    SpawnKey();
                }
            }
        }
    
        public void OnBossKilled()
        {
            Debug.LogWarning("Boss enemy killed");
            bossesKilled++;
    
            if (bossesKilled >= bossesRequiredForPortal  && !portalSpawned)
            {
                if (AudioManager1.Instance != null)
                    AudioManager1.Instance.PlaySoundEffects(AudioManager1.Instance.popup);
                if (popupManager != null)
                    popupManager.ShowPopup("FLOOR BOSS DEFEATED!\n FIND THE TREASURE!");
                SpawnKey();
            }
        }
    
        void SpawnKey()
        {
            Vector3 spawnPosition = FindSpawnPosition();
            if (spawnPosition != Vector3.zero)
            {
                GameObject key = Instantiate(keyPrefab, spawnPosition, Quaternion.identity);
                KeyItem keyItem = key.GetComponent<KeyItem>();
                if (keyItem != null)
                {
                    keyItem.OnKeyCollected += OnKeyCollected;
                }
                portalSpawned = true;
            }
        }
    
        Vector3 FindSpawnPosition()
        {
            if (mapGenerator == null || mapGenerator.floorTileMap == null || mapGenerator.rooms == null || mapGenerator.rooms.Count == 0)
            {
                Debug.LogWarning("Fail to find map in LevelManager script");
                return Vector3.zero;
            }
            int attemps = 50;
            for (int i = 0; i < attemps; i++)
            {
                Room randomRoom = mapGenerator.rooms[Random.Range(0, mapGenerator.rooms.Count)];
                if (randomRoom.tiles.Count == 0) continue;
    
                Coord randomTile = randomRoom.tiles[Random.Range(0, randomRoom.tiles.Count)];
                Vector3 worldPos = mapGenerator.floorTileMap.CellToWorld(new Vector3Int(randomTile.tileX, randomTile.tileY, 0)) + new Vector3(0.5f, 0.5f, 0);
    
                Collider2D[] colliders = Physics2D.OverlapCircleAll(worldPos, 0.4f);
                bool canSpawn = true;
                foreach (Collider2D collider in colliders)
                {
                    if (collider.CompareTag("Enemy") || collider.CompareTag("Decoration") || 
                        collider.CompareTag("Prop") || collider.CompareTag("Player"))
                    {
                        canSpawn = false;
                        break;
                    }
                }
                if (canSpawn)
                {
                    Debug.Log("Key spot found");
                    return worldPos;
                }
    
            }
    
            Debug.LogError($"Place for key not found");
            return Vector3.zero;
        }
    
    
        void OnKeyCollected()
        {
            SpawnPortal();
        }
    
        void SpawnPortal()
        {
            if (AudioManager1.Instance != null)
                AudioManager1.Instance.PlaySoundEffects(AudioManager1.Instance.popup);
            popupManager.ShowPopup("FIND THE PORTAL");
            Vector3 spawnPosition = FindSpawnPosition();
            if (spawnPosition != Vector3.zero)
            {
                Instantiate(portalPrefab, spawnPosition, Quaternion.identity);
            }
        }
    
        public void LoadNextLevel()
        {
            StartCoroutine(TransitionToNextLevel());
        }
    
        IEnumerator TransitionToNextLevel()
        {
            if (player  == null)
            {
                yield break;
            }
    
            PlayerStats playerStats = player.GetComponent<PlayerStats>();
            if (playerStats == null)
            {
                Debug.Log("Fail to get component in playerStats");
                yield break;
            }
            PlayerInventory inventory = player.GetComponent<PlayerInventory>();
            int savedHealth = (int)playerStats.CurrentHealth;
            int savedLevel = playerStats.level;
            int savedExp = playerStats.experience;
    
            SaveCurrentEnemies();
    
            if (DestructiblePropManager.Instance != null)
            {
                DestructiblePropManager.Instance.ReturnAllPropsToPool();
            }
    
    
            if (mapGenerator != null)
            {
                mapGenerator.GenerateMap();
            }
    
            yield return new WaitForSeconds(0.1f);
    
            if (mapGenerator  != null)
            {
                Vector3 safeSpawnPos = mapGenerator.GetSafeMainRoomSpawnPosition1();
                if (safeSpawnPos != Vector3.zero)
                {
                    player.position = safeSpawnPos;
                }
                else
                {
                    Debug.LogWarning("Failed to find safe spawn position, using deafult");
                }
            }
    
            // RĘCZNIE INICJALIZUJ PROP MANAGER JEŚLI NIE ZROBIŁ TEGO AUTOMATYCZNIE
            if (DestructiblePropManager.Instance != null &&
                DestructiblePropManager.Instance.propsPool.Count == DestructiblePropManager.Instance.poolSize && 
                DestructiblePropManager.Instance.activePropsCount == 0)
            {
                Debug.Log("Manually initializing Prop Manager...");
                DestructiblePropManager.Instance.Initialize(mapGenerator.rooms);
            }
    
            playerStats.CurrentHealth = savedHealth;
            playerStats.level = savedLevel;
            playerStats.experience = savedExp;
    
            RestoreEnemies();
    
            currentLevel++;
            bossesKilled = 0;
            portalSpawned = false;
            levelStartTime = Time.time;
    
            IncreaseDifficulty();
    
            if (GameManager.instance != null)
            {
                GameManager.instance.IncreaseDungeonLevel();
            }
    
            if (AudioManager1.Instance != null)
                AudioManager1.Instance.PlaySoundEffects(AudioManager1.Instance.portal);
            FindAnyObjectByType<PopupManager>().ShowPopup("NEXT AREA REACHED!");
        }
    
        void SaveCurrentEnemies()
        {
            currentEnemies.Clear();
            GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
            foreach (GameObject enemy in enemies)
            {
                currentEnemies.Add(enemy);
            }
        }
    
        void RestoreEnemies()
        {
            foreach (GameObject enemy in currentEnemies)
            {
                if (enemy != null)
                {
                    Vector3 spawnPos = GetRandomSpawnPosition();
                    enemy.transform.position = spawnPos;
                }
            }
            currentEnemies.Clear();
        }
    
        Vector3 GetRandomSpawnPosition()
        {
            Vector3 spawnPosition = Vector3.zero;
            if (enemySpawner != null && enemySpawner.relativeSpawnPoints != null && enemySpawner.relativeSpawnPoints.Count > 0)
            {
                spawnPosition = enemySpawner.relativeSpawnPoints[UnityEngine.Random.Range(0, enemySpawner.relativeSpawnPoints.Count)].position;
            }
            return spawnPosition;
        }
    
        void IncreaseDifficulty()
        {
            if (enemySpawner != null)
            {
                enemySpawner.allEnemiesLimit = Mathf.RoundToInt(enemySpawner.allEnemiesLimit * 1.2f);
            }
        }
    
        public void RegisterEnemy(GameObject enemy)
        {
            if (!currentEnemies.Contains(enemy))
            {
                currentEnemies.Add(enemy);
            }
        }
    
        public void UnregisterEnemy(GameObject enemy)
        {
            if (currentEnemies.Contains(enemy))
            {
                currentEnemies.Remove(enemy);
            }
        }
    
    }

    GameManager is mostly the same tbh

    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
        }
    
        // 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("Dungeon Proggresion")]
        public int dungeonLevel = 1;
    
        [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;
    
        [Header("Current Stat Displays")]
        public TMP_Text currentHealthDisplay;
        public TMP_Text currentRecoveryDisplay;
        public TMP_Text currentMoveSpeedDisplay;
        public TMP_Text currentMightDisplay;
        public TMP_Text currentProjectileSpeedDisplay;
        public TMP_Text currentMagnetDisplay;
    
        [Header("Results Screen Displays")]
        public Image chosenCharacterImage;
        public TMP_Text chosenCharacterName;
        public TMP_Text levelReachedDisplay;
        public TMP_Text timeSurvivedDisplay;
        public List<Image> chosenWeaponsUI = new List<Image>(6);
        public List<Image> chosenPassiveItemsUI = new List<Image>(6);
    
        [Header("Stopwatch")]
        public float timeLimit; // The time limit in seconds
        float stopwatchTime; // The current time elapsed since the stopwatch started
        public TMP_Text stopwatchDisplay;
    
        // Flag to check if the game is over
        public bool isGameOver = false;
    
        // Flag to check if the player is choosing their upgrades
        public bool choosingUpgrade = false;
    
        // Reference to the player's game object
        public GameObject playerObject;
    
        void Awake()
        {
            //Warning check to see if there is another singleton of this kind already in the game
            if (instance == null)
            {
                instance = this;
                //świeżo dodane
                DontDestroyOnLoad(gameObject);
    
                // DODAJ TO - CZYSZCZENIE PRZY STARCIE GRY
                //CleanupAllPickupsAtStart();
            }
            else
            {
                Debug.LogWarning("EXTRA " + this + " DELETED");
                Destroy(gameObject);
            }
    
            DisableScreens();
        }
    
        void Update()
        {
            // Define the behavior for each state
            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:
                    // Code for the game over state
                    if (!isGameOver)
                    {
                        isGameOver = true;
                        Time.timeScale = 0f; //Stop the game entirely
                        Debug.Log("Game is over");
                        DisplayResults();
                    }
                    break;
                case GameState.LevelUp:
                    if (!choosingUpgrade)
                    {
                        choosingUpgrade = true;
                        Time.timeScale = 0f; //Pause the game for now
                        Debug.Log("Upgrades shown");
                        levelUpScreen.SetActive(true);
                    }
                    break;
                default:
                    Debug.LogWarning("STATE DOES NOT EXIST");
                    break;
            }
        }
        public void IncreaseDungeonLevel()
        {
            dungeonLevel++;
        }
    
        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.SetAsFirstSibling(); // or 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)
            {
                // Fade the text to the right alpha value
                tmPro.color = new Color(tmPro.color.r, tmPro.color.g, tmPro.color.b, 1 - t / duration);
    
                if (target)
                {
                    yOffset += speed * Time.deltaTime;
                    if (rect != null)
                    {
                        rect.position = referenceCamera.WorldToScreenPoint(lastKnownposition + new Vector3(0, yOffset));
    
                    }
                }
                else
                {
                    // If target iis dead, just pan up where the text is at
                    if (rect != null)
                    {
                        rect.position += new Vector3(0, speed * Time.deltaTime, 0);
                    }
                }
    
    
                // 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)
        {
            currentState = newState;
        }
    
        public void PauseGame()
        {
            if (currentState != GameState.Paused)
            {
                previousState = currentState;
                ChangeState(GameState.Paused);
                Time.timeScale = 0f; // Stop the game
                pauseScreen.SetActive(true); // Enable the pause screen
    
                if (playerObject != null)
                {
                    PlayerStats playerStats = playerObject.GetComponent<PlayerStats>();
                    if (playerStats != null)
                    {
                        playerStats.RefreshStatusUI();
                    }
    
                }
                else
                    Debug.LogWarning("Attempt to get actual stats failed.");
                Debug.Log("Game is paused");
            }
        }
    
        public void ResumeGame()
        {
            if (currentState == GameState.Paused)
            {
                ChangeState(previousState);
                Time.timeScale = 1f; // Resume the game
                pauseScreen.SetActive(false); //Disable the pause screen
                Debug.Log("Game is resumed");
            }
        }
    
        // 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;
            ChangeState(GameState.GameOver);
        }
    
        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 void AssignChosenWeaponsAndPassiveItemsUI(List<PlayerInventory.Slot> chosenWeaponsData, List<PlayerInventory.Slot> chosenPassiveItemsData)
        {
            // Check that both lists have the same length
            if (chosenWeaponsData.Count != chosenWeaponsUI.Count || chosenPassiveItemsData.Count != chosenPassiveItemsUI.Count)
            {
                Debug.LogError("Chosen weapons and passive items data lists have different lengths");
                return;
            }
    
            // Assign chosen weapons data to chosenWeaponsUI
            for (int i = 0; i < chosenWeaponsUI.Count; i++)
            {
                // Check that the sprite of the corresponding element in chosenWeaponsData is not null
                if (chosenWeaponsData[i].image.sprite)
                {
                    // Enable the corresponding element in chosenWeaponsUI and set its sprite to the corresponding sprite in chosenWeaponsData
                    chosenWeaponsUI[i].enabled = true;
                    chosenWeaponsUI[i].sprite = chosenWeaponsData[i].image.sprite;
                }
                else
                {
                    // If the sprite is null, disable the corresponding element in chosenWeaponsUI
                    chosenWeaponsUI[i].enabled = false;
                }
            }
    
            // Assign chosen passive items data to chosenPassiveItemsUI
            for (int i = 0; i < chosenPassiveItemsUI.Count; i++)
            {
                // Check that the sprite of the corresponding element in chosenPassiveItemsData is not null
                if (chosenPassiveItemsData[i].image.sprite)
                {
                    // Enable the corresponding element in chosenPassiveItemsUI and set its sprite to the corresponding sprite in chosenPassiveItemsData
                    chosenPassiveItemsUI[i].enabled = true;
                    chosenPassiveItemsUI[i].sprite = chosenPassiveItemsData[i].image.sprite;
                }
                else
                {
                    // If the sprite is null, disable the corresponding element in chosenPassiveItemsUI
                    chosenPassiveItemsUI[i].enabled = false;
                }
            }
        }
    
        void UpdateStopwatch()
        {
            stopwatchTime += Time.deltaTime;
    
            UpdateStopwatchDisplay();
    
            if (stopwatchTime >= timeLimit)
            {
                playerObject.SendMessage("Kill");
            }
        }
    
        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()
        {
            AudioManager1.Instance.PlaySoundEffects(AudioManager1.Instance.levelUp);
            ChangeState(GameState.LevelUp);
            playerObject.SendMessage("RemoveAndApplyUpgrades");
        }
    
        public void EndLevelUp()
        {
            choosingUpgrade = false;
            Time.timeScale = 1f;    //Resume the game
            levelUpScreen.SetActive(false);
            ChangeState(GameState.Gameplay);
        }
    }

    Sory for this long intro, I wanted to explain it clearly but I’m not sure if I did it proprely.

    has upvoted this post.
    #18803
    Alp Apustaja
    Level 10
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    Hello Patryk! Thanks for sharing your code and explaining your issue in detail. It sounds like you’re encountering a problem where the variables in your GameManager disappear after the player dies and you restart the game. Let’s break down the potential causes and solutions.

    Potential Issues

    1. Singleton Pattern: Both LevelManager and GameManager use the singleton pattern with DontDestroyOnLoad. If you have multiple instances of either manager, it could lead to unexpected behavior. Make sure that you only have one instance of each manager in your scene.

    2. Game State Reset: When the player dies, you might not be resetting the game state properly. If the GameManager is not re-initializing its variables when the game restarts, it could lead to the loss of data.

    3. Scene Reloading: If you are reloading the scene when the player dies, ensure that you are not inadvertently destroying the GameManager instance. If the scene reloads and the GameManager is not set up to retain its state, it will reset.

    4. Variable Initialization: Check if you are re-initializing your variables in the Awake or Start methods of GameManager when the game restarts. If you are not, the variables may retain their values from the previous game session.

    Suggested Solutions

    1. Check Singleton Implementation: Ensure that your singleton implementation is correct. You can add debug logs to confirm that only one instance of GameManager and LevelManager exists.

      void Awake()
      {
          if (instance == null)
          {
              instance = this;
              DontDestroyOnLoad(gameObject);
              Debug.Log("GameManager instance created");
          }
          else
          {
              Debug.LogWarning("Another GameManager instance was destroyed");
              Destroy(gameObject);
          }
      }
    2. Reset Game State on Death: When the player dies, make sure to reset the game state properly. You can create a method in GameManager to reset all necessary variables.

      public void ResetGame()
      {
          dungeonLevel = 1; // Reset dungeon level
          // Reset other variables as needed
          isGameOver = false;
          // Additional reset logic
      }
    3. Handle Game Over Logic: In your GameOver method, ensure that you are calling the reset method before restarting the game or transitioning to the results screen.

      public void GameOver()
      {
          timeSurvivedDisplay.text = stopwatchDisplay.text;
          ChangeState(GameState.GameOver);
          ResetGame(); // Reset the game state here
      }
    4. Debugging: Add debug logs to track the values of your variables at different points in the game. This will help you identify where the values are being lost.

    Conclusion

    By ensuring that your singleton pattern is correctly implemented, resetting your game state properly, and adding debugging information, you should be able to identify and fix the issue with your GameManager. If you continue to have problems, feel free to share more details, and I’ll be happy to help further! Good luck with your game development!

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

    Hi Patryk, I’m glad you enjoy the series!

    Will need you to tell me a little bit more about what you’re doing. Which are the variables you are trying to save? Is it the whole Game Manager?

    And which part of the series are you on right now?

Viewing 3 posts - 1 through 3 (of 3 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: