Continue Button not working as supposed to in Asteroid Avoider game

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.

This one puzzled me for a bit, as when I paused the game after returning from Continue, the StarSparrow object under the player was missing… which means that something must have destroyed it.

So I went through each script, and I could find nothing that would destroy the player’s ship object.
So outside of play, I looked at the child object itself and discovered that there was an Asteroid script on it. This was causing the ship to destroy itself when the player collides with another asteroid. Remove that component, and you’ll be back up and running (flying).

1 Like

Big thanks for helping me fix the player issue! You were spot on :heart_eyes:—I had an extra script that was messing things up.

Quick question: Now my Score UI isn’t showing up after an ad. Got any quick tips?

Thanks a bunch!

ok i fixed it by adding this line to continuegame method in gameoverhandler class

if (scoreUI != null) scoreUI.SetActive(true);

and now after closing the ad i can see that score ui is active and working as supposed to. Thank you so much :pray:

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms