Game Manager Reference is Invalid

I am making a game and the basics of it is fruits spawn on the bottom of the screen, and when you click it, it should disappear and add a point to score. Right now for each fruit object, I have a game manager and for each fruit there is a fruit handler. The one for the second and third fruit are the same, but the first one has some other code as well.
I tried to make all game managers and fruit handlers work exactly the same so I am not sure why only the first one is working.

I realize I should only have one Game Manager, but is there a way to fix my error using this method?

Side by side comparison of scripts below and screenshot

FruitClickHandler.cs

public class FruitClickHandler : MonoBehaviour
{
    private GameManager gameManager; 
    GameObject gameManagerObject;
    private void Start()
    { 
        gameManagerObject = GameObject.FindGameObjectWithTag("Game Manager");

        gameManager = GameObject.Find("Game Manager").GetComponent<GameManager>();
        if (gameManager == null)
        {
            Debug.LogError("GameManager not found in the scene.");
        }
    }


    private void OnMouseDown()
    {
        // Check if the GameManager reference is valid
        if (gameManager != null)
        {
            gameManager.UpdateScore(gameManagerObject);
        }
        else
        {
            Debug.LogError("GameManager reference is invalid.");
        }

        Destroy(gameObject);
    }

    // Handle collisions with other objects
    private void OnTriggerEnter(Collider other)//if object goes out of frame
    {
        Destroy(gameObject);
    }

}

FruitClickHandler1.cs

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

public class FruitClickHandler1 : MonoBehaviour
{
    private GameManager gameManager1; // Reference to the GameManager component
    GameObject gameManagerObject;
    private void Start()
    {
         gameManagerObject = GameObject.FindGameObjectWithTag("Game Manager 1");

        if (gameManagerObject != null)
        {
            gameManager1 = gameManagerObject.GetComponent<GameManager>();
            if (gameManager1 == null)
            {
                Debug.LogError("GameManager1 component not found on Game Manager 1 object.");
            }
        }
        else
        {
            Debug.LogError("Game Manager 1 object not found in the scene.");
        }
    }

    private void OnMouseDown()
    {
        if (gameManager1 != null)
        {
            gameManager1.UpdateScore(gameManagerObject); // Call the UpdateScore method on GameManager
        }
        else
        {
            Debug.LogError("GameManager reference is invalid.");
        }

        Destroy(gameObject);
    }

    private void OnTriggerEnter(Collider other)
    {
        Destroy(gameObject);
    }
}

GameManager.cs

public class GameManager : MonoBehaviour
{
    public List<GameObject> targets;
...other variables

    public int publicIndex;
    public static GameManager instance;
    void Start()
    {
        instance = this;
        string[] additionEquations = {
    "1+1", "1+2", "1+3", "1+4", "1+5", "1+6", "1+7", "1+8", "1+9", "1+10",
    ...
        equationList = new List<string>(additionEquations);
        string[] additionAnswers = {
    "2", "0", "0", "5", "0", "0", "8", "0", "0", "11",
    "0", "0",...
        answerList = new List<string>(additionAnswers);

        StartCoroutine(SpawnTarget());
        score = 0;

    }

    // Update is called once per frame
    void Update()
    {
        
    }

    IEnumerator SpawnTarget() {
        while (true)
        {
            yield return new WaitForSeconds(spawnRate);

            publicIndex = Random.Range(0, equationList.Count);
            string randomItem = equationList[publicIndex];
            string randomAnswer = answerList[publicIndex];
            answerGM0 = randomAnswer;
            Debug.Log("GameManager0: answerGM0 = " + answerGM0); 

            Vector3 spawnPosition = RandomSpawnPos();

            GameObject fruit = Instantiate(targets[Random.Range(0, targets.Count)], spawnPosition, Quaternion.identity);

            Rigidbody fruitRigidbody = fruit.GetComponent<Rigidbody>();
            fruitRigidbody.AddForce(RandomForce(), ForceMode.Impulse);
            fruitRigidbody.AddTorque(Vector3.forward * RandomTorque(), ForceMode.Impulse);

            // Create and configure the answer text
            GameObject answerTextObj = new GameObject("AnswerText");
            answerTextObj.transform.SetParent(fruit.transform);
            TextMeshPro answerText = answerTextObj.AddComponent<TextMeshPro>();
            ...

            // Position the answer text relative to the fruit
            answerText.transform.localPosition = answerTextOffset;

            UpdateEquationText(randomItem);
        }
    }

    private void UpdateEquationText(string equation) {
        equationText.text = "Equation: " + equation;
    }


    Vector3 RandomSpawnPos()
    {
        float randomX = Random.Range(-13, -13);
        float randomY = -1;
        Vector3 spawnPosition = new Vector3(randomX, randomY, 0f);
        return spawnPosition;
    }
    Vector3 RandomForce() {
        return Vector3.up * Random.Range(mixSpeed, maxSpeed);
    }
    float RandomTorque() {
        return Random.Range(-maxTorque, maxTorque);
    }

    public void UpdateScore(GameObject clickedObject) {
        Debug.Log("Passed through GM1");
        if (publicIndex % 3 == 0) {
            score += int.Parse(answerGM0);
            scoreText.text = "Score: " + score;
        }
        else {
            Debug.Log("Wrong Fruit");
        }

    }


}

GameManager1.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System;
using UnityEngine.UI;
using Random = UnityEngine.Random;
public class GameManager1 : MonoBehaviour
{
    public List<GameObject> targets;
...other variable



    void Start()
    {
        StartCoroutine(SpawnTarget());
        score = 0;
        instance = this;
        string[] additionAnswers = {
    "0", "3", "0", "0", "6", "0", "0", "9", "0", "0",
...
        answerList = new List<string>(additionAnswers);
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    IEnumerator SpawnTarget()
    {
        while (true) {
            yield return new WaitForSeconds(spawnRate);
            publicIndex = gameManager.publicIndex;
            answerGM1 = answerList[publicIndex];
            Debug.Log("GameManager1: answerGM1 = " + answerGM1); 


            Vector3 spawnPosition = RandomSpawnPos();

            GameObject fruit = Instantiate(targets[Random.Range(0, targets.Count)], spawnPosition, Quaternion.identity);

            Rigidbody fruitRigidbody = fruit.GetComponent<Rigidbody>();
            fruitRigidbody.AddForce(RandomForce(), ForceMode.Impulse);
            fruitRigidbody.AddTorque(Vector3.forward * RandomTorque(), ForceMode.Impulse);

            // Create and configure the answer text
            GameObject answerTextObj = new GameObject("AnswerText");
            answerTextObj.transform.SetParent(fruit.transform);
            TextMeshPro answerText = answerTextObj.AddComponent<TextMeshPro>();
            ...

            // Position the answer text relative to the fruit
            answerText.transform.localPosition = answerTextOffset;


    }
    }
    public void CheckAnswer()
    {
        // Replace this with your actual answer-checking logic
        Debug.Log("GameManager1: CheckAnswer called");
    }
    Vector3 RandomSpawnPos()
    {
        float randomX = Random.Range(-4, -4);
        float randomY = -1;
        Vector3 spawnPosition = new Vector3(randomX, randomY, 0f);
        return spawnPosition;
    }
    Vector3 RandomForce() {
        return Vector3.up * Random.Range(mixSpeed, maxSpeed);
    }
    float RandomTorque() {
        return Random.Range(-maxTorque, maxTorque);
    }

    public void UpdateScore(GameObject clickedObject) {
        Debug.Log("Passed through GM1");
        if (publicIndex % 3 == 0) {
            score += int.Parse(answerGM1);
            scoreText.text = "Score: " + score;
        }
        else {
            Debug.Log("Wrong Fruit");
        }



    }
}

It may be a lot to read, but I have been stuck on this for a long time and I would really appreciate any suggestions or if you have a different way that I should do it. I can attach more screenshots if needed as well. Thanks.

1 Like

Hi,

Inside the FruitClickHandler1 class, you are trying to get a reference to a GameManager class inside the Start method, but I believe what you wanted to do is to get a reference to your GameManager1 class. So you’d have to change the variable gameManager1 type, and change the GetComponent type.

As you said, it is best practice to keep one GameManager inside your project if they have the same purpose.
If you want an easy access to your GameManager from multiple GameObjects, I suggest you to make it a Singleton. You should find everything that you need here : Level up your code with game programming patterns (unity.com)