0

Okay so before I begin, Yes I have looked online to find this answer. I've followed advice on multiple other questions, gone through the unity documentation, and done more than a few web searches and nothing I've found so far has solved the error. I'm sure someone will take one look at this and know immediately what's wrong, but as for me, I just can't find it.

Now that that's out of the way Here's the problem. I'm making a Breakout clone and I had everything done, everything working properly. I've got one static class that takes care of the scoring and score related variables, so that other scripts can access them easily. I wanted to practice some basic saving and loading with PlayerPrefs, so I added something for highscores. It's pretty much independent of the other classes, but once I finished that, I started getting a Null Reference Exception in a script that has been done for hours, and was working fine.

I appreciate any help you might have, and any tips for preventing this kind of error the next time around. Sorry It's such a long question.

Here's the full error:

NullReferenceException: Object reference not set to an instance of an object
MenuManager.ActivateLose () (at Assets/Scripts/MenuScripts/MenuManager.cs:31)
Scoring.CheckGameOver () (at Assets/Scripts/Scoring.cs:64)
Scoring.LifeLost () (at Assets/Scripts/Scoring.cs:51)
DeadZone.OnTriggerEnter2D (UnityEngine.Collider2D other) (at Assets/Scripts/DeadZone.cs:22)

And here are the three scripts listed in said error:

using UnityEngine;
using System.Collections;

public class DeadZone : MonoBehaviour 
{

    public GameObject ballPrefab;
    public Transform paddleObj;

    GameObject ball;

    void Update () 
    {
        ball = GameObject.FindGameObjectWithTag("Ball");
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        //if the object that entered the trigger is the ball
        if(other.tag == "Ball")
        {
            Scoring.LifeLost();
            //destroy it, and instantiate a new one above where the paddle currently is
            Destroy(ball);
            paddleObj.transform.position = new Vector2(0, -2.5f);
            (Instantiate(ballPrefab, new Vector2(paddleObj.transform.position.x, paddleObj.transform.position.y + 0.3f), Quaternion.identity) as GameObject).transform.parent = paddleObj;
        }
    }
}

using UnityEngine;
using System.Collections;

public static class Scoring
{

    public static GameObject scoreValue;
    public static TextMesh scoreText;
    public static int score;

    static int multiplier = 0;
    static int consecutiveBreaks = 0;
    static int lives = 3;
    static int totalBricks;
    static int remainingBricks;

    public static GameObject menuManagerObj;
    public static MenuManager menuManager = new MenuManager();

    static void Awake()
    {
        scoreValue = GameObject.FindGameObjectWithTag("Scoring");
        scoreText = scoreValue.GetComponent<TextMesh>();
        menuManagerObj = GameObject.FindGameObjectWithTag("MenuManager");
        //menuManager = menuManagerObj.GetComponent<MenuManager>();
    }

    public static void BrickDestroyed()
    {
        if(scoreValue == null && scoreText == null)
        {
            scoreValue = GameObject.FindGameObjectWithTag("Scoring");
            scoreText = scoreValue.GetComponent<TextMesh>();
        }

        remainingBricks--;
        consecutiveBreaks++;
        multiplier = 1 + (consecutiveBreaks % 5);
        score += 10 * multiplier;
        CheckGameOver();
        scoreText.text = score + "";
    }

    public static void LifeLost()
    {
        consecutiveBreaks = 0;
        multiplier = 1;
        score -= 100;
        lives--;
        LivesDisplay.SetLives(lives);
        CheckGameOver();
        scoreText.text = score + "";
    }

    public static void SetBrickCount(int brickCount)
    {
        totalBricks = brickCount;
        remainingBricks = totalBricks;
    }

    public static void CheckGameOver()
    {
        //lose condition
        if(lives < 0) menuManager.ActivateLose();

        //win condition
        if(remainingBricks == 0) menuManager.ActivateWin();

    }

}

using UnityEngine;
using System.Collections;

public class MenuManager :  MonoBehaviour
{

    public GameObject winMenu;
    public GameObject loseMenu;
    public GameObject pauseMenu;
    public HighScoreManager highScores;

    bool isGamePaused = true;

    void Awake()
    {
        winMenu = GameObject.FindGameObjectWithTag("Win");
        loseMenu = GameObject.FindGameObjectWithTag("Lose");
        pauseMenu = GameObject.FindGameObjectWithTag("Pause");
    }

    public void ActivateWin()
    {
        Time.timeScale = 0f;
        winMenu.transform.position = new Vector3(0, 0, -1);
        highScores.CompareToHighScores(Scoring.score);
    }

    public void ActivateLose()
    {
        Time.timeScale = 0f;
        loseMenu.transform.position = new Vector3(0, 0, -1);
    }

    void ActivatePause()
    {
        if(isGamePaused)
        {
            Time.timeScale = 0f;
            pauseMenu.transform.position = new Vector3(0, 0, -1);
        }
        else
        {
            Time.timeScale = 1f;
            pauseMenu.transform.position = new Vector3(35, 0, -1);
        }
        isGamePaused = !isGamePaused;
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Escape))
        {
            ActivatePause();
        }
    }

}
Evan M
  • 11
  • 3
  • 2
    Possible duplicate of [What is a NullReferenceException and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Ron Beyer Oct 08 '15 at 20:59
  • 1
    Make sure the script has the `loseMenu` reference set properly. You can also see the real-time value of it in the properties inspector, when the game is running. – SimpleVar Oct 08 '15 at 21:01
  • As far as I know it's set properly. I tried dragging the game object into the inspector directly, and I've tried getting it with FindGameObjectWithTag and neither seemed to have any effect. I've watched it while it was running and it doesn't seem to change at all. – Evan M Oct 08 '15 at 21:05
  • You could make the `loseMenu` into a property, and put a breakpoint in the setter, or `Debug.Log(value)` inside of it, to see when it ever becomes null. Do other activation functions work properly for you? – SimpleVar Oct 08 '15 at 21:07
  • Hmm, sounds like it could be usefull. How do I go about doing that? – Evan M Oct 08 '15 at 21:08
  • Read about C# properties and backing-field. – SimpleVar Oct 08 '15 at 21:08
  • Alright thanks! I'll give it a look. – Evan M Oct 08 '15 at 21:10
  • Are you sure that `MenuManager.Awake` is getting called before `ActivateLose`? Rather than adding a property, why not add: `if (loseMenu == null) Debug.Log("null");` before the call. – theB Oct 08 '15 at 21:10
  • I thought that Awake would automatically run first since it's called when the object is created? Or am I mistaken? And I added that before the call, and it does come out null. But I'm still not sure why, or how to fix it. If MenuManager.Awake isn't being called before the method is, how do I remedy that? – Evan M Oct 08 '15 at 21:12
  • What happens if you set the references in the editor and then remove the Awake method altogether? `GameObject.FindGameObjectWithTag` could return null for some reason. Really just put a breakpoint in every method and check what actually happens. – SimpleVar Oct 08 '15 at 21:51
  • By the way, could be that the `Awake` method really isn't fired because it isn't `public`. I recall it might have that quirk. – SimpleVar Oct 08 '15 at 21:56
  • The problem with settig them in the editor is that it won't work on the static ones, and they are half the trouble. I've tried the non static ones in the editor, and wind up with the same error. Also just tried removing the Awake method, tried making it public, tried initializing outside and in, nothing helped. – Evan M Oct 08 '15 at 22:48
  • I have no idea what I've done to this It's got me stumped and frustrated. And I just know that once I figure it out I'm gonna feel dumb for not seeing it sooner. Thank you both for your help so far! – Evan M Oct 08 '15 at 22:50

1 Answers1

0

The problem is that Scoring is not a MonoBehaviour so the Awake method never gets called. You can try to initialize the fields in a static constructor

static Scoring()
{
    scoreValue = GameObject.FindGameObjectWithTag("Scoring");
    scoreText = scoreValue.GetComponent<TextMesh>();
    menuManagerObj = GameObject.FindGameObjectWithTag("MenuManager");
    //menuManager = menuManagerObj.GetComponent<MenuManager>();
}

or make the Awake method public and call it from another MonoBehaviour.

Pluto
  • 3,911
  • 13
  • 21