Continue Button not working as supposed to in Asteroid Avoider game

Hi there,

I am facing this issue while running the game :

small gif continue button

and here are my cs files:

using UnityEngine;
using UnityEngine.Advertisements;

public class AdManager : MonoBehaviour, IUnityAdsInitializationListener, IUnityAdsLoadListener, IUnityAdsShowListener
{
    [SerializeField] private string androidGameId;
    [SerializeField] private string iOSGameId;
    [SerializeField] private bool testMode = true;

    [SerializeField] private string androidAdUnitId;
    [SerializeField] private string iOSAdUnitId;

    public static AdManager instance;

    private string gameId;
    private string adUnitID;
    private GameOverHandler gameOverHandler;

    private void Awake()
    {
        if (instance != null && instance != this)
        {
            Destroy(gameObject);
        }
        else
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
            InitializeAds();
        }
    }

    private void InitializeAds()
    {
        Debug.Log("Initializing Ads");
#if UNITY_IOS
        gameId = iOSGameId;
        adUnitID = iOSAdUnitId;
#elif UNITY_ANDROID
        gameId = androidGameId;
        adUnitID = androidAdUnitId;
#endif
        if (!Advertisement.isInitialized)
        {
            Advertisement.Initialize(gameId, testMode, this);
        }
    }

    public void ShowAd(GameOverHandler gameOverHandlerInstance)
    {
        this.gameOverHandler = gameOverHandlerInstance;
        Debug.Log("Trying to load an ad");
        Advertisement.Load(adUnitID, this);
    }

    public void OnUnityAdsAdLoaded(string placementId)
    {
        Debug.Log("Ad successfully loaded");
        Advertisement.Show(placementId, this);
    }

    public void OnUnityAdsFailedToLoad(string placementId, UnityAdsLoadError error, string message)
    {
        Debug.Log($"Failed to load ad: {error} - {message}");
    }

    public void OnUnityAdsShowComplete(string placementId, UnityAdsShowCompletionState showCompletionState)
    {
        Debug.Log("Ad Show Complete Callback Triggered");
        Debug.Log($"Show Completion State: {showCompletionState}");

        if (placementId.Equals(adUnitID) && showCompletionState.Equals(UnityAdsShowCompletionState.COMPLETED))
        {
            Debug.Log("Ad completed, continuing the game");
            gameOverHandler.ContinueGame();
        }
        else
        {
            Debug.Log($"Ad not completed: PlacementId = {placementId}, Completion State = {showCompletionState}");
        }
    }


    public void OnUnityAdsShowFailure(string placementId, UnityAdsShowError error, string message)
    {
        Debug.Log($"Error showing Ad Unit {adUnitID}: {error} - {message}");
    }

    public void OnUnityAdsShowStart(string placementId)
    {
        Debug.Log("Ad Show Started");
    }

    public void OnUnityAdsShowClick(string placementId)
    {
        Debug.Log("Ad Clicked");
    }

    public void OnInitializationComplete()
    {
        Debug.Log("Unity Ads Initialization Complete");
    }

    public void OnInitializationFailed(UnityAdsInitializationError error, string message)
    {
        Debug.Log($"Unity Ads Initialization Failed: {error} - {message}");
    }
}

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

public class ScoreSystem : MonoBehaviour
{
    

    [SerializeField] private TMP_Text scoreText;
    [SerializeField] private float scoreMultiplier;

    private bool shouldCount = true;
    private float score;

    void Update()
    {
        if (!shouldCount) { return; }

        score += Time.deltaTime * scoreMultiplier;

        scoreText.text = Mathf.FloorToInt(score).ToString();
    }

    public int EndTimer()
    {
        shouldCount = false;

        scoreText.text = string.Empty;

        return Mathf.FloorToInt(score);
    }
}

Do you have any idea about what i am missing here?

I can’t tell what the feedback messages are saying.
Are you getting Ad completed, continuing the Game or Ad not completed?

i see Ad completed, continuing the game and Trying to continue the game and player should now be active debugs but when ad is visible i can see that game still continues as there are constant feedbacks like these :" Initial viewport position: (0.29, 0.47, 10.00), Updated viewport position: (0.29, 0.47, 10.00) "

The game itself will still be “running” in the background as the ad plays.

Are you calling gameObject.SetActive(false); in PlayerHealth? That should stop the PlayerMovement from Updating.

here is my player health class:

using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
    [SerializeField] private GameOverHandler gameOverHandler;

    public void Crash()
    {
        gameOverHandler.EndGame();

        gameObject.SetActive(false);
    }
}

it should not be moving while the ad is visible right? I am not able to close the ad :thinking:

That, I’m not sure about the cause at all.
Are you getting these Debugs?

Ad Show Complete Callback Triggered
Show Completion State (with a completion state message)
Ad completed, continuing the game

yes but after clicking close all of the debugs are Initial viewport position, Updated viewport position, initial viewport position and such

That almost looks like you’re stuck in a loop, like AdManager.ShowAd() is getting called over and over again.
Paste in your GameOverHandler.cs and we’ll take a look.

here it is:

using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameOverHandler : MonoBehaviour
{
    [SerializeField] private TMP_Text gameOverText;
    [SerializeField] private ScoreSystem scoreSystem;
    [SerializeField] private GameObject gameOverDisplay;
    [SerializeField] private AsteroidSpawner asteroidSpawner;

    [SerializeField] private GameObject player;  
    [SerializeField] private GameObject scoreUI; 

    public void EndGame()
    {
        Debug.Log("Game Over - Ending the game");
        asteroidSpawner.enabled = false;
        int finalScore = scoreSystem.EndTimer();
        gameOverText.text = $"Your Score: {finalScore}";
        gameOverDisplay.SetActive(true);

        if (player != null) player.SetActive(false);
        if (scoreUI != null) scoreUI.SetActive(false);
    }

    public void ContinueGame()
    {
        Debug.Log("Trying to continue the game");

        // Call ShowAd() from AdManager here
        AdManager.instance.ShowAd(this);

        if (asteroidSpawner != null)
        {
            asteroidSpawner.enabled = true;
        }

        gameOverDisplay.SetActive(false);

        if (player != null)
        {
            player.SetActive(true);
            Debug.Log("Player should now be active: " + player.activeSelf);
        }
        if (scoreUI != null)
        {
            scoreUI.SetActive(true);
            Debug.Log("Score UI should now be active: " + scoreUI.activeSelf);
        }
    }


    public void PlayAgain()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    public void ReturnToMenu()
    {
        SceneManager.LoadScene("Menu");
    }
}


The issue is the ContinureGame method.

In the course repo, we have two distinct functions, ContinueButton() and ContinueGame()
ContinueButton is linked from the Button in the UI, and calls ShowAd()

    public void ContinueButton()
    {
        AdManager.Instance.ShowAd(this);

        continueButton.interactable = false;
    }

While ConinueGame() deals just with the restarting of the game, and is called for AdManager.OnUnityShowAdsComplete()

    public void ContinueGame()
    {
        scoreSystem.StartTimer();

        player.transform.position = Vector3.zero;
        player.SetActive(true);
        player.GetComponent<Rigidbody>().velocity = Vector3.zero;

        asteroidSpawner.enabled = true;

        gameOverDisplay.gameObject.SetActive(false);
    }

What’s happening in your ContinueGame is that you’re starting an ad, and then immediately resetting the player. Then when ShowAdComplete finishes, it calls the method again, which… starts an ad, and restarts the game, explaining both behaviors we’re seeing

  • Ads playing over and over again in a cycle
  • Game playing while ad is running.

i’ve seen the course repo now and updated the classes with added codes and included this ContinueButton function as well but now when game ends and I click to continuebutton there are no ads showing up :thinking:

using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class GameOverHandler : MonoBehaviour
{
    [SerializeField] private TMP_Text gameOverText;
    [SerializeField] private ScoreSystem scoreSystem;
    [SerializeField] private GameObject gameOverDisplay;
    [SerializeField] private AsteroidSpawner asteroidSpawner;

    [SerializeField] private GameObject player;  
    [SerializeField] private GameObject scoreUI;
    [SerializeField] private Button continueButton;

   
    public void ContinueButton()
    {
        AdManager.Instance.ShowAd(this);

        continueButton.interactable = false;
    }


    public void EndGame()
    {
        Debug.Log("Game Over - Ending the game");
        asteroidSpawner.enabled = false;
        int finalScore = scoreSystem.EndTimer();
        gameOverText.text = $"Your Score: {finalScore}";
        gameOverDisplay.SetActive(true);

        if (player != null) player.SetActive(false);
        if (scoreUI != null) scoreUI.SetActive(false);
    }

    public void ContinueGame()
    {
        scoreSystem.StartTimer();

        player.transform.position = Vector3.zero;
        player.SetActive(true);
        player.GetComponent<Rigidbody>().velocity = Vector3.zero;

        asteroidSpawner.enabled = true;

        gameOverDisplay.gameObject.SetActive(false);
    }



    public void PlayAgain()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    public void ReturnToMenu()
    {
        SceneManager.LoadScene("MainMenu");
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Advertisements;

public class AdManager : MonoBehaviour, IUnityAdsInitializationListener, IUnityAdsLoadListener, IUnityAdsShowListener
{
    [SerializeField] private string androidGameId;
    [SerializeField] private string iOSGameId;
    [SerializeField] private bool testMode = true;

    [SerializeField] private string androidAdUnitId;
    [SerializeField] private string iOSAdUnitId;

    public static AdManager Instance;

    private string gameId;
    private string adUnitId;
    private GameOverHandler gameOverHandler;

    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
        }
        else
        {
            InitialiseAds();

            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
    }

    private void InitialiseAds()
    {
#if UNITY_IOS
        gameId = iOSGameId;
        adUnitId = iOSAdUnitId;
#elif UNITY_ANDROID
        gameId = androidGameId;
        adUnitId = androidAdUnitId;
#elif UNITY_EDITOR
        gameId = androidGameId;
        adUnitId = androidAdUnitId;
#endif

        if (!Advertisement.isInitialized)
        {
            Advertisement.Initialize(gameId, testMode, this);
        }
    }

    public void OnInitializationComplete()
    {
        Debug.Log("Unity Ads initialization complete.");
    }

    public void OnInitializationFailed(UnityAdsInitializationError error, string message)
    {
        Debug.Log($"Unity Ads Initialization Failed: {error.ToString()} - {message}");
    }

    public void OnUnityAdsAdLoaded(string placementId)
    {
        Advertisement.Show(placementId, this);
    }

    public void OnUnityAdsFailedToLoad(string placementId, UnityAdsLoadError error, string message)
    {
        Debug.Log($"Error loading Ad Unit {adUnitId}: {error.ToString()} - {message}");
    }

    public void OnUnityAdsShowFailure(string placementId, UnityAdsShowError error, string message)
    {
        Debug.Log($"Error showing Ad Unit {adUnitId}: {error.ToString()} - {message}");
    }

    public void OnUnityAdsShowStart(string placementId)
    {

    }

    public void OnUnityAdsShowClick(string placementId)
    {

    }

    public void OnUnityAdsShowComplete(string placementId, UnityAdsShowCompletionState showCompletionState)
    {
        if (placementId.Equals(adUnitId)
            && showCompletionState.Equals(UnityAdsShowCompletionState.COMPLETED))
        {
            gameOverHandler.ContinueGame();
        }
    }

    public void ShowAd(GameOverHandler gameOverHandler)
    {
        this.gameOverHandler = gameOverHandler;

        Advertisement.Load(adUnitId, this);
    }
}

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

public class ScoreSystem : MonoBehaviour
{
    

    [SerializeField] private TMP_Text scoreText;
    [SerializeField] private float scoreMultiplier;

    private bool shouldCount = true;
    private float score;

    void Update()
    {
        if (!shouldCount) { return; }

        score += Time.deltaTime * scoreMultiplier;

        scoreText.text = Mathf.FloorToInt(score).ToString();
    }

    public void StartTimer()
    {
        shouldCount = true;
    }


    public int EndTimer()
    {
        shouldCount = false;

        scoreText.text = string.Empty;

        return Mathf.FloorToInt(score);
    }
}

Often, this can be caused by advertisements not being available at the time of the Load.
I’ve made a slightly modified version of the AdManager that deviates from Nathan’s script, but follows what some of the assistants at the Unity Forums
Here’s a link to the topic I created. Note that this isn’t a panacea. Sometimes the ads simply don’t work. Sometimes, looking for the Debug.Logs generated in the callback functions in LogCat can give an insight to what’s happening.
Here’s the link to my revised script:

thank you for these but i’ve updated the admanager class with your revised admanager class and still i don’t see any ads showing up

it seems i did not add the continue button gameobject to the game over handler and that’s why ad was not showing up. Now ad is showing but after I close the ad, player is not visible on the scene but it is active. I see that on the editor, player becomes enabled on and if i touch anywhere on the screen i can see position logs changes.

Interesting… I was going to ask if you were re-enabling the player, but going through your code, you are.

Can you share a screenshot of the player’s inspector, along with a copy of your PlayerMovement.cs script?

thanks for checking out. here are the thing you need:

using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class GameOverHandler : MonoBehaviour
{
    [SerializeField] private TMP_Text gameOverText;
    [SerializeField] private ScoreSystem scoreSystem;
    [SerializeField] private GameObject gameOverDisplay;
    [SerializeField] private AsteroidSpawner asteroidSpawner;

    [SerializeField] private GameObject player;
    [SerializeField] private GameObject scoreUI;
    [SerializeField] private Button continueButton;

    public void ContinueButton()
    {
        AdManager.Instance.ShowAd(this);
        Debug.Log("ContinueButton clicked. Attempting to show ad.");
        continueButton.interactable = false;
    }

    void Start()
    {
        if (continueButton != null)
        {
            continueButton.onClick.AddListener(() => ContinueButton());
        }
        else
        {
            Debug.LogError("continueButton is not assigned in GameOverHandler.");
        }
    }



    public void EndGame()
    {
        Debug.Log("Game Over - Ending the game");
        asteroidSpawner.enabled = false;
        Debug.Log("AsteroidSpawner disabled.");
        int finalScore = scoreSystem.EndTimer();
        gameOverText.text = $"Your Score: {finalScore}";
        gameOverDisplay.SetActive(true);
        Debug.Log("GameOverDisplay activated.");

        if (player != null) player.SetActive(false);
        Debug.Log("Player GameObject disabled.");
        if (scoreUI != null) scoreUI.SetActive(false);
    }

    public void ContinueGame()
    {
        scoreSystem.StartTimer();
        Debug.Log("Score timer started.");

        player.transform.position = Vector3.zero;
        Debug.Log("Player position reset to zero.");

        player.SetActive(true);
        Debug.Log("Player GameObject set to active.");

        player.GetComponent<Rigidbody>().velocity = Vector3.zero;

        asteroidSpawner.enabled = true;
        Debug.Log("AsteroidSpawner enabled.");

        gameOverDisplay.SetActive(false);
        Debug.Log("GameOverDisplay deactivated.");
    }


    public void PlayAgain()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    public void ReturnToMenu()
    {
        SceneManager.LoadScene("MainMenu");
    }
}

oops sorry for the wrong class sharing here is the one you needed :sweat_smile:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour
{
    [SerializeField] private float forceMagnitude;
    [SerializeField] private float maxVelocity;
    [SerializeField] private float rotationSpeed;

    private Rigidbody rb;
    private Camera mainCamera;

    private Vector3 movementDirection;

    void Start()
    {
        rb = GetComponent<Rigidbody>();

        mainCamera = Camera.main;
    }

    void Update()
    {
        ProcessInput();

        KeepPlayerOnScreen();

        RotateToFaceVelocity();
        Debug.Log("Player Position: " + transform.position);
    }

    void FixedUpdate()
    {
        if (movementDirection == Vector3.zero) { return; }

        rb.AddForce(movementDirection * forceMagnitude * Time.deltaTime, ForceMode.Force);

        rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxVelocity);
    }

    private void ProcessInput()
    {
        if (Touchscreen.current.primaryTouch.press.isPressed)
        {
            Vector2 touchPosition = Touchscreen.current.primaryTouch.position.ReadValue();

            // Log the touch position before converting it to world position
            

            // Check for infinite values in the touch position
            if (float.IsInfinity(touchPosition.x) || float.IsInfinity(touchPosition.y))
            {
                Debug.Log("Touch Position contains Infinity");
                return;
            }

            Vector3 worldPosition = mainCamera.ScreenToWorldPoint(touchPosition);

            
            

            movementDirection = transform.position - worldPosition;
            movementDirection.z = 0f;
            movementDirection.Normalize();
        }
        else
        {
            movementDirection = Vector3.zero;
        }
    }

    private void KeepPlayerOnScreen()
    {
        Vector3 newPosition = transform.position;
        Vector3 viewportPosition = mainCamera.WorldToViewportPoint(transform.position);
        bool positionChanged = false;

        

        if (viewportPosition.x > 1)
        {
            viewportPosition.x = 0;
            positionChanged = true;
        }
        else if (viewportPosition.x < 0)
        {
            viewportPosition.x = 1;
            positionChanged = true;
        }

        if (viewportPosition.y > 1)
        {
            viewportPosition.y = 0;
            positionChanged = true;
        }
        else if (viewportPosition.y < 0)
        {
            viewportPosition.y = 1;
            positionChanged = true;
        }

       

        if (positionChanged)
        {
            newPosition = mainCamera.ViewportToWorldPoint(viewportPosition);
            newPosition.z = transform.position.z;
            transform.position = newPosition;

           
        }
    }



    private void RotateToFaceVelocity()
    {
        if (rb.velocity == Vector3.zero) { return; }

        Quaternion targetRotation = Quaternion.LookRotation(rb.velocity, Vector3.back);

        transform.rotation = Quaternion.Lerp(
            transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
    }
}

I’m not seeing anything in the code to cause this. I’ll need to take a closer look.
Zip up your project and upload it to https://gdev.tv/projectupload and I’ll see if I can figure out what’s causing this issue.
Be sure to remove the Library folder to conserve space.

ok I’ve uploaded the project but i guess i am not able to share its link through here is that correct?

It doesn’t need a link here, I get a page with uploaded projects on it. I’m getting the same version of Unity installed, and then I’ll be able to take a closer look.

Privacy & Terms