Null Exception error on a Dictionary?

Hi guys i have been studying Unity recently, and as I small project to start learn, Im recreating the classic “Pong” game.

I have so far 3 main scripts, one is a Game Manager, one is for Constants and another for the Ball Collision.
i am getting an error when i call the method “Add Score” from the Ball Collision to the Constants script, however, as I understood I not using an empty value since I have set the Dictonary at the beggining.

Here is my Constants Script:

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

public class Constants
{
    //GAME SCORE STRINGS
    public string player1Name = "Player1";
    public string player2Name = "Player2";
    public string flowName = "Flow";
    public string highName = "Highscore";

    // GAME SCORE INTEGER
    [SerializeField]
    private int player1Score = 0;
    [SerializeField]
    private int player2Score = 0;
    [SerializeField]
    private int flowScore = 0;
    [SerializeField]
    private int highScore = 0;


    // GAMESCORE DICTIONARY
    public Dictionary<string, int> gamescore;

    private void Awake()
    {
        gamescore = new Dictionary<string, int>
        {
            {player1Name, player1Score },
            {player2Name, player2Score },
            {flowName, flowScore },
            {highName, highScore },
        };
    }


    // METHODS

    // ADD TO THE SCORE VALUE
    public void AddScore(string name, int score)
    {
        if (!gamescore.ContainsKey(name))
        {
            Debug.LogError("Unrecognized score type " + name);
        }
        gamescore[name] += score;
    }

    //UPDATE THE HIGH SCORE AND RETURN THE HIGH SCORE VALUE
    public int ScoreUpdate(string flowscore, int score)
    {
        if (score >= highScore)
        {
            highScore = score;
            return highScore;
        }
        else
        {
            return highScore;
        }
    }

    //GET SCORE FROM NAME
    public int GetScore(string name)
    {
        if (!gamescore.ContainsKey(name))
        {
            Debug.LogError("Unrecognized score type " + name);
        }
        return gamescore[name];
    }

    //RESET SCORE
    public void ResetScore(string name)
    {
        if (!gamescore.ContainsKey(name))
        {
            Debug.LogError("Unrecognized score type " + name);
        }

        gamescore[name] = 0;
    }

}

I m getting error at line 44

here is my Ball Script:

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

public class BallCollision : MonoBehaviour
{

    public GameObject ballPrefab;
    private float ballHits = 0f;
    private Constants constants = new Constants();
    private GameManager gameManager;


    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Player")
        {
            ImpulseBall();
        }
    }

    public void OnTriggerEnter(Collider collider)
    {
        switch (collider.gameObject.tag)
        {
            case "Goal":
                constants.AddScore("Player1", 1);
                gameManager.ContinueGame();
                break;
            case "Player2 Goal":
                constants.AddScore("Player2", 1);
                gameManager.ContinueGame();
                break;
            default:
                break;
        }
    }


    void DestroyBall()
    {
        ballHits = 0;
        Destroy(gameObject);
    }


    void ImpulseBall()
    {
        Vector3 ballLocation = transform.position;
        if (ballLocation.z <= 0)
        {
            ballPrefab.GetComponent<Rigidbody>().AddForce(0, 0, (2f + ballHits), ForceMode.Impulse);
        } else
        {
            ballPrefab.GetComponent<Rigidbody>().AddForce(0, 0, (-2f - Mathf.Abs(ballHits)), ForceMode.Impulse);
        }
        ballHits += 0.2f;
    }


    private void Awake()
    {
        gameManager = GetComponent<GameManager>();
    }

    // Start is called before the first frame update
    void Start()
    {
       
    }

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

and finally my game manager script:

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

public class GameManager : MonoBehaviour
{
    public GameObject Ball;
    public Transform spawnposition;
    private float randomNumberX;
    private float randomNumberZ;
    private Constants constants = new Constants();

    void spawnBall()
    {
        GameObject ball = Instantiate(Ball) as GameObject;
        ball.transform.position = spawnposition.position;
        ball.GetComponent<Rigidbody>().AddForce(randomNumberX, 0, randomNumberZ, ForceMode.Impulse);
    }

    void getRandomPositionBall()
    {
        float Sort = Random.Range(0f, 2f);
        if (Sort >= 1f)
        {
            randomNumberZ = -3f;
        } else
        {
            randomNumberZ = 3f;
        }
        randomNumberX = Random.Range(-1f, 1f);
    }

    public void ContinueGame()
    {

        int player1 = constants.GetScore("Player1");
        int player2 = constants.GetScore("Player2");

        if (player1 >= 3)
        {
            constants.ResetScore("Player1");
            constants.ResetScore("Player2");
            Debug.Log("Player1 Wins");
            //Stop game
        }
        if (player2 >= 3)
        {
            constants.ResetScore("Player1");
            constants.ResetScore("Player2");
            Debug.Log("Player2 Wins");
            //stop game
        }
        spawnBall();
    }


    // Start is called before the first frame update

    void Start()
    {
        getRandomPositionBall();
        spawnBall();
    }

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

From I can understand, all methods that are being used outside the Constant’s script are getting Null reference, what i am doing wrong?

Constants doesn’t inherit from Monobehaviour, which means Awake doesn’t auto run, so your Dictionary is null.

You would need to inherit from Monobehaviour and have it on a gameobject in the scene.

Also note that your other two scripts create a new Constants object, which means those two scripts don’t even point to the same Object, thus they aren’t going to behave how you think…

1 Like

Hi Brathnann, thanks for the reply!
Maybe if i change the awake for Start it will resolve this part of the issue?
And how can I call the constant object that i want?

Im kinda lost in this part, because I thought that i was referencing that script by doing the new (script).

Awake and Start are functions that Unity will magically invoke on scripts that inherit from Monobehaviour. If your script does not inherit from Monobehaviour, Awake and Start are just regular functions that won’t do anything unless you explicitly call them.

I think it would work best if you used a constructor instead of Awake for your Constants class.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Constants
{
    //GAME SCORE STRINGS
    public string player1Name = "Player1";
    public string player2Name = "Player2";
    public string flowName = "Flow";
    public string highName = "Highscore";
    // GAME SCORE INTEGER
    [SerializeField]
    private int player1Score = 0;
    [SerializeField]
    private int player2Score = 0;
    [SerializeField]
    private int flowScore = 0;
    [SerializeField]
    private int highScore = 0;
    // GAMESCORE DICTIONARY
    public Dictionary<string, int> gamescore;
    public Constants()
    {
        gamescore = new Dictionary<string, int>
        {
            {player1Name, player1Score },
            {player2Name, player2Score },
            {flowName, flowScore },
            {highName, highScore },
        };
    }
    // METHODS
    // ADD TO THE SCORE VALUE
    public void AddScore(string name, int score)
    {
        if (!gamescore.ContainsKey(name))
        {
            Debug.LogError("Unrecognized score type " + name);
        }
        gamescore[name] += score;
    }
    //UPDATE THE HIGH SCORE AND RETURN THE HIGH SCORE VALUE
    public int ScoreUpdate(string flowscore, int score)
    {
        if (score >= highScore)
        {
            highScore = score;
            return highScore;
        }
        else
        {
            return highScore;
        }
    }
    //GET SCORE FROM NAME
    public int GetScore(string name)
    {
        if (!gamescore.ContainsKey(name))
        {
            Debug.LogError("Unrecognized score type " + name);
        }
        return gamescore[name];
    }
    //RESET SCORE
    public void ResetScore(string name)
    {
        if (!gamescore.ContainsKey(name))
        {
            Debug.LogError("Unrecognized score type " + name);
        }
        gamescore[name] = 0;
    }
}

A constructor would work, but you’ll still have the issue that both your scripts are creating a new instance of the object, which means if you change the Constants object in one script, the other script Constants object will not be changed. So either you need a central script that both scripts can access (like a manager script), be static, or inherit from monobehaviour and create references to the gameobject that has the script on it, in which case you wouldn’t use a constructor.