Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Issues with Implementing 'Continue Game' Logic After Ads in Unity

Discussion in 'Getting Started' started by boredcook, Nov 18, 2023.

  1. boredcook

    boredcook

    Joined:
    Jul 18, 2023
    Posts:
    1
    Hi There,

    I'm facing challenges with my 'Continue Game' feature in a 2D shooter game. The game is supposed to pause when the player dies, show an ad, and then continue from the exact state (player position, score, enemies on screen) upon resuming. Currently, the game does not resume correctly after the first continue; it restarts from the beginning.

    What I want to achieve:

    1. Ensure the game resumes from the exact state after watching an ad.
    2. Maintain the proper game state across multiple 'continue' attempts without restarting.
    Steps I've taken:

    • Implemented a GameState class to save and load the game state.
    • Used DontDestroyOnLoad to persist the GameManager across scenes.
    • Attempted to use a state machine pattern with IGameState interface for different game states, which introduced more errors so i reverted to a previous state and removed all of IGameState interface related stuff
    I would greatly appreciate guidance on best practices for managing game states in Unity and resolving the continue feature's erratic behavior.

    I am a total noob here and gamedevelopment but you may check some related classes below.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using TMPro;
    4. using System.Collections;
    5.  
    6.  
    7. public class UIGameOver : MonoBehaviour
    8. {
    9.     [SerializeField] TextMeshProUGUI scoreText;
    10.     [SerializeField] GameObject scoreUI;
    11.     [SerializeField] Button continueButton;
    12.     [SerializeField] AdManager adManager;
    13.     [SerializeField] EnemySpawner enemySpawner;
    14.     [SerializeField] AssetDynamicJoystick joystick;
    15.     [SerializeField] private Button leaderboardButton;
    16.  
    17.     GameManager gameManager;
    18.     ScoreKeeper scoreKeeper;
    19.  
    20.     public static UIGameOver Instance;
    21.  
    22.  
    23.     private void Awake()
    24.     {
    25.         // Finding and assigning the GameManager instance
    26.         gameManager = FindObjectOfType<GameManager>();
    27.         scoreKeeper = FindObjectOfType<ScoreKeeper>();
    28.         Instance = this;
    29.         if (gameManager == null)
    30.         {
    31.             Debug.LogError("GameManager instance not found by UIGameOver.");
    32.         }
    33.  
    34.         // Finding and assigning the ScoreKeeper instance
    35.         scoreKeeper = ScoreKeeper.Instance;
    36.         if (scoreKeeper == null)
    37.         {
    38.             Debug.LogError("ScoreKeeper instance not found by UIGameOver.");
    39.         }
    40.         else
    41.         {
    42.             Debug.Log("ScoreKeeper instance found by UIGameOver.");
    43.         }
    44.  
    45.         // Setting up the Continue button
    46.         if (continueButton != null)
    47.         {
    48.             continueButton.onClick.AddListener(HandleContinueClicked);
    49.         }
    50.         else
    51.         {
    52.             Debug.LogError("ContinueButton not assigned in the inspector.");
    53.         }
    54.  
    55.         if (leaderboardButton != null)
    56.         {
    57.             leaderboardButton.onClick.AddListener(GameManager.Instance.LoadLeaderboardScene);
    58.         }
    59.         else
    60.         {
    61.             Debug.LogError("LeaderboardButton not assigned in the inspector.");
    62.         }
    63.     }
    64.  
    65.  
    66.     public void HandleGameOver()
    67.     {
    68.         Debug.Log("HandleGameOver called.");
    69.  
    70.         GameManager.isGameOver = true;
    71.  
    72.         // Ensure the UIGameOver GameObject is active
    73.         gameObject.SetActive(true);
    74.  
    75.         // Directly call UpdateScoreText
    76.         UpdateScoreText();
    77.  
    78.         // Deactivate unnecessary UI components and game objects
    79.         if (scoreUI) scoreUI.SetActive(false);
    80.  
    81.         enemySpawner?.ClearEnemies();
    82.  
    83.         // Ensure the scoreText GameObject is active
    84.         if (scoreText.gameObject.activeSelf == false)
    85.         {
    86.             scoreText.gameObject.SetActive(true);
    87.             Debug.Log("ScoreText GameObject activated.");
    88.         }
    89.     }
    90.  
    91.  
    92.  
    93.  
    94.  
    95.     public void HandleContinueClicked()
    96.     {
    97.         Debug.Log("UIGameOver: HandleContinueClicked called.");
    98.  
    99.         if (adManager)
    100.         {
    101.             Debug.Log("UIGameOver: Calling AdManager.ShowAd()...");
    102.  
    103.             // Subscribe the ContinueGame method of GameManager to the onAdFinished event.
    104.             adManager.onAdFinished += FindObjectOfType<GameManager>().ContinueGame;
    105.  
    106.             // Pass the references of UIGameOver and GameManager to the ShowAd method.
    107.             adManager.ShowAd(this, FindObjectOfType<GameManager>());
    108.  
    109.             // The UIGameOver UI is hidden so that it doesn’t interfere with the ad or the resumed game.
    110.             gameObject.SetActive(false);
    111.         }
    112.         else
    113.         {
    114.             Debug.LogError("UIGameOver: AdManager reference is missing.");
    115.         }
    116.     }
    117.  
    118.  
    119.  
    120.  
    121.     public void ContinueGameAfterAd()
    122.     {
    123.         Debug.Log("Continuing game after ad...");
    124.         gameManager.ContinueGame();
    125.         gameObject.SetActive(false);
    126.     }
    127.  
    128.  
    129.     public void HandlePlayAgainClicked()
    130.     {
    131.         gameManager.PlayAgain();
    132.     }
    133.  
    134.     private IEnumerator DelayedUpdateScoreText()
    135.     {
    136.         yield return new WaitForSeconds(0.1f); // wait for a short moment
    137.         UpdateScoreText();
    138.     }
    139.  
    140.     private void UpdateScoreText()
    141.     {
    142.         Debug.Log("UpdateScoreText called.");
    143.  
    144.         // Ensure the ScoreKeeper instance is found
    145.         if (scoreKeeper == null)
    146.         {
    147.             scoreKeeper = FindObjectOfType<ScoreKeeper>();
    148.         }
    149.  
    150.         if (scoreKeeper != null)
    151.         {
    152.             scoreText.text = $"You Scored:\n{scoreKeeper.Score}";
    153.             Debug.Log($"Score displayed: {scoreKeeper.Score}");
    154.         }
    155.         else
    156.         {
    157.             scoreText.text = "Score data unavailable.";
    158.             Debug.LogError("ScoreKeeper instance is not accessible in UpdateScoreText.");
    159.         }
    160.     }
    161.  
    162.     public void HideGameOverUI()
    163.     {
    164.         gameObject.SetActive(false);
    165.     }
    166.  
    167. }
    168.  
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.SceneManagement;
    3. using System.Collections;
    4.  
    5. public class GameManager : MonoBehaviour
    6. {
    7.    
    8.     public GameObject player;
    9.     public GameObject scoreUI;
    10.     public EnemySpawner enemySpawner;
    11.     public AssetDynamicJoystick joystick;
    12.  
    13.     public GameObject gameOverUIPrefab; // Reference to your Game Over UI Prefab
    14.  
    15.     private GameObject currentGameOverUI; // To keep track of the current Game Over UI instance
    16.     public static bool isGameOver = false;
    17.    
    18.     public static GameManager Instance;
    19.     public static bool shouldContinueGame = false;
    20.     public AdManager adManager;
    21.  
    22.  
    23.     private void Awake()
    24.     {
    25.         Debug.Log("GameManager Awake called. Instance ID: " + GetInstanceID());
    26.         if (Instance == null)
    27.         {
    28.             Instance = this;
    29.            
    30.         }
    31.         else if (Instance != this)
    32.         {
    33.             Destroy(gameObject);
    34.         }
    35.         isGameOver = false;
    36.     }
    37.  
    38.     private void Update()
    39.     {
    40.         if (shouldContinueGame)
    41.         {
    42.             ContinueGame();
    43.             shouldContinueGame = false;
    44.         }
    45.     }
    46.  
    47.     public void RequestContinueGame()
    48.     {
    49.         shouldContinueGame = true;
    50.         Debug.Log("GameManager: RequestContinueGame() called.");
    51.     }
    52.  
    53.     public void GameOver()
    54.     {
    55.         // Pause game mechanics
    56.         Time.timeScale = 0;
    57.  
    58.         // Instantiate Game Over UI
    59.         if (currentGameOverUI == null)
    60.         {
    61.             currentGameOverUI = Instantiate(gameOverUIPrefab);
    62.             Debug.Log("GameManager: GameOverUI instantiated.");
    63.         }
    64.         else
    65.         {
    66.             Debug.Log("GameManager: currentGameOverUI is not null.");
    67.         }
    68.  
    69.         DestroyHealthPickups();
    70.     }
    71.  
    72.  
    73.  
    74.     public void ContinueGame()
    75.     {
    76.         Debug.Log("GameManager: ContinueGame() called.");
    77.  
    78.        
    79.         if (player != null)
    80.         {
    81.             player.SetActive(true);
    82.         }
    83.         else
    84.         {
    85.             Debug.LogError("GameManager: Player reference is missing.");
    86.         }
    87.  
    88.         Health playerHealthComponent = player.GetComponent<Health>();
    89.         if (playerHealthComponent != null)
    90.         {
    91.             Debug.Log("GameManager: Player found, attempting to call Revive().");
    92.             playerHealthComponent.Revive();
    93.  
    94.             // Calculate the amount needed to fully heal the player
    95.             int healAmount = playerHealthComponent.GetMaxHealth() - playerHealthComponent.GetHealth();
    96.  
    97.             // Heal the player
    98.             playerHealthComponent.Heal(healAmount);
    99.         }
    100.         else
    101.         {
    102.             Debug.LogError("GameManager: Health component not found in the Player.");
    103.         }
    104.  
    105.         if (scoreUI != null)
    106.         {
    107.             scoreUI.SetActive(true);
    108.         }
    109.         else
    110.         {
    111.             Debug.LogError("GameManager: ScoreUI reference is missing.");
    112.         }
    113.  
    114.        
    115.         if (enemySpawner != null)
    116.         {
    117.             enemySpawner.RestartWave();
    118.         }
    119.         else
    120.         {
    121.             Debug.LogError("GameManager: EnemySpawner reference is missing.");
    122.         }
    123.  
    124.        
    125.  
    126.  
    127.         if (joystick != null)
    128.         {
    129.             joystick.gameObject.SetActive(true);
    130.         }
    131.         else
    132.         {
    133.             Debug.LogError("GameManager: Joystick reference is missing.");
    134.         }
    135.  
    136.        
    137.         if (currentGameOverUI != null)
    138.         {
    139.             Destroy(currentGameOverUI);
    140.             currentGameOverUI = null;
    141.         }
    142.  
    143.        
    144.         isGameOver = false;
    145.  
    146.        
    147.         Time.timeScale = 1;
    148.     }
    149.  
    150.  
    151.  
    152.  
    153.  
    154.  
    155.  
    156.     // Coroutine to destroy the Game Over UI after a short delay
    157.     private IEnumerator DestroyGameOverUIAfterDelay()
    158.     {
    159.         yield return new WaitForSeconds(1f); // Wait for 1 second or any suitable delay
    160.         if (currentGameOverUI != null)
    161.         {
    162.             Destroy(currentGameOverUI);
    163.             currentGameOverUI = null;
    164.             Debug.Log("Game Over UI destroyed.");
    165.         }
    166.     }
    167.  
    168.     public void PlayAgain()
    169.     {
    170.         Debug.Log("EnemySpawner: Start method called.");
    171.         GameManager.isGameOver = false;
    172.         if (currentGameOverUI != null)
    173.         {
    174.             Destroy(currentGameOverUI);
    175.             currentGameOverUI = null;
    176.         }
    177.         ScoreKeeper scoreKeeper = FindObjectOfType<ScoreKeeper>();
    178.         if (scoreKeeper != null)
    179.         {
    180.             scoreKeeper.ResetScore();
    181.         }
    182.         // Load the game scene to start over
    183.         SceneManager.LoadScene("Game");
    184.     }
    185.  
    186.     public void LoadMainMenu()
    187.     {
    188.         // Reset the game over UI
    189.         if (currentGameOverUI != null)
    190.         {
    191.             Destroy(currentGameOverUI);
    192.             currentGameOverUI = null;
    193.         }
    194.  
    195.         ScoreKeeper scoreKeeper = FindObjectOfType<ScoreKeeper>();
    196.  
    197.         // Reset the score
    198.         if (scoreKeeper != null)
    199.         {
    200.             scoreKeeper.ResetScore();
    201.         }
    202.         // Load the main menu scene
    203.         SceneManager.LoadScene("MainMenu");
    204.  
    205.     }
    206.  
    207.     public void LoadLeaderboardScene()
    208.     {
    209.         // Optionally save the score if needed
    210.         PlayerPrefs.SetInt("LastScore", ScoreKeeper.Instance.Score);
    211.  
    212.         // Load the leaderboard scene
    213.         SceneManager.LoadScene("LeaderBoard");
    214.     }
    215.  
    216.  
    217.     public void DestroyHealthPickups()
    218.     {
    219.         HealthPickup[] healthPickups = FindObjectsOfType<HealthPickup>();
    220.         foreach (var pickup in healthPickups)
    221.         {
    222.             Destroy(pickup.gameObject);
    223.         }
    224.     }
    225.  
    226. }
    227.  

    Any help will be much appreciated as I am totally stuck here and could not proceed anymore.
    Thanks in advance...