Null Reference Exception Unity Course [duplicate] - c#

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 months ago.
I working through an online lesson and getting a Null reference exception. I know it's an extremely common error but neither I or the online help for the course have been able to figure it out. So I'm hoping for some insight here.
Level Manager Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelManager : MonoBehaviour
{
[SerializeField] float sceneLoadDelay = 2f;
ScoreKeeper scoreKeeper;
void Start()
{
scoreKeeper = FindObjectOfType<ScoreKeeper>();
}
public void LoadGame()
{
scoreKeeper.ResetScore();
SceneManager.LoadScene("MainGame");
}
public void LoadMainMenu()
{
SceneManager.LoadScene("MainMenu");
}
public void LoadGameOver()
{
StartCoroutine(WaitAndLoad("GameOver", sceneLoadDelay));
}
public void QuitGame()
{
Debug.Log("Quitting Game...");
Application.Quit();
}
IEnumerator WaitAndLoad(string sceneName, float delay)
{
yield return new WaitForSeconds(delay);
SceneManager.LoadScene(sceneName);
}
}
Score Keeper Script:
public class ScoreKeeper : MonoBehaviour
{
int score;
static ScoreKeeper instance;
void Awake()
{
ManageSingleton();
}
void ManageSingleton()
{
if (instance != null)
{
gameObject.SetActive(false);
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(gameObject);
}
}
public int GetScore()
{
return score;
}
public void ModifyScore(int value)
{
score += value;
Mathf.Clamp(score, 0, int.MaxValue);
Debug.Log(score);
}
public void ResetScore()
{
score = 1;
}
}
Error is in the level manager at this line: scoreKeeper.ResetScore();
I should add that the a Level Manager and a Score Keeper Object were created with the scripts attached and are in each scene.

In the Hierarchy look for at least 2 GameObjects present or not
One with ScoreKeeper.cs attached
Another with LevelManager.cs attached
If this is ok then open LevelManager.cs and add private keyword before the line ScoreKeeper scoreKeeper; as you are already finding and attaching it in Start() method, like this below
private ScoreKeeper scoreKeeper;

The issue is that you need to call ScoreKeeper.instance.ResetScore(). You have it setup as a singleton. Otherwise you will need to add a concrete reference to an instance in your level manager.
You also need to make the instance public:
public static ScoreKeeper instance;

Related

I have a script which I have used on two objects and, Rigidbody2d.bodytype changes to static but is not changing back to dynamic for one game object

Here is my script code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ControlSpike : MonoBehaviour
{
private static ControlSpike _instance = null;
public static ControlSpike Instance { get { return _instance; } }
public Rigidbody2D spikeBody;
public void Awake()
{
_instance = null;
if (_instance != null && _instance != this)
{
}
else
{
_instance = this;
}
spikeBody.bodyType = RigidbodyType2D.Static;
}
// Start is called before the first frame update
void Start()
{
spikeBody.bodyType = RigidbodyType2D.Static;
}
// Update is called once per frame
void Update()
{
}
public void DropSpikes()
{
if (DrawingManager.Instance.paths.Contains(DrawingManager.Instance.clone) && VehicleSimpleControl._instance.RacePress)
{
spikeBody.bodyType = RigidbodyType2D.Dynamic;
spikeBody.gravityScale = 10f;
}
}
}
The rigidbody.body type changes bodytype of one gameobject to dynamic but doesnt change the bodytype of the second gameobject to dynamic. Both get changed to static though. What could be wrong?
Thanks in Advance!
So, I created a manager for this in which I created two rigidbodies references. I passed the references of my objects in this manager and it worked. Basically, the code is same I just removed the script from the gameobjects and created a manager for them instead.

UnityException: GetActiveScene is not allowed to be called from a MonoBehaviour constructor

I'm trying to make a save level system and I keep on getting this error.
UnityException: GetActiveScene is not allowed to be called from a MonoBehaviour constructor
I've tried searching this up, but there were no results. Here is the code I used:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class EndLevel : MonoBehaviour
{
public PlayerMovement pm;
public GameObject completeLevelUI;
// Start is called before the first frame update
void Start() {
}
// Update is called once per frame
void Update() {
}
void OnCollisionEnter (Collision collisionInfo) {
if(collisionInfo.collider.tag == "Finish") {
Debug.Log("You beat the level!");
pm.enabled = false;
completeLevelUI.SetActive(true);
Level = Level + 1;
PlayerPrefs.SetFloat("Level", Level);
Debug.Log("Saved");
Invoke("NextLevel", 3);
}
}
public void NextLevel() {
SceneManager.LoadScene (SceneManager
.GetActiveScene().buildIndex + 1);
}
}
Any Ideas about the error?
You have to get the current active Scene in the Start() or Awake() methods.
Example with Start():
private int sceneNumber;
private void Start() {
sceneNumber = SceneManager.GetActiveScene().buildIndex;
}
As an alternative solution you could also use a Lazzy Getter. Which means that the value won't get stale between when the scene loads and when you use it, which might matter with other pieces of data.
Example with Lazzy Getter:
private int sceneNumber {
get {
return SceneManager.GetActiveScene().buildIndex;
}
}
When you use either of those solutions, you can now simply call scenenumber + 1 in your SceneManager.Load() function call instead.
Additionally you need to ensure that you are calling an IEnumerator, instead of Invoking the Function call. If you want to delay the scene loading.
Function Call:
private void OnCollisionEnter (Collision collisionInfo) {
...
StartCoroutine(NextLevel(3f));
...
}
private IEnumerator NextLevel(float seconds) {
yield return new WaitForSeconds(seconds);
SceneManager.LoadScene(sceneNumber + 1);
}

Singleton – extra script not destroyed?

I want to have a singleton which will store, update and show player score through all levels (scenes), but something works wrong.
This my singletone script GameStatus.cs:
using UnityEngine;
using TMPro;
public class GameStatus : MonoBehaviour
{
public static GameStatus instance;
[SerializeField] int pointsPerBlock = 50;
[SerializeField] TextMeshProUGUI scoreText;
[SerializeField] public static int currentScore = 0;
private void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(gameObject);
}
}
public void AddToScore()
{
currentScore += pointsPerBlock;
scoreText.text = currentScore.ToString();
}
}
I also have another script for objects player need to destroy, called Block.cs. Here it is:
using UnityEngine;
public class Block : MonoBehaviour
{
Level level;
GameStatus gameStatus;
private void Start()
{
level = FindObjectOfType<Level>();
gameStatus = FindObjectOfType<GameStatus>();
level.CountBreakableBlocks();
}
private void OnCollisionEnter2D(Collision2D collision)
{
DestroyBlock();
}
private void DestroyBlock()
{
level.BlockDestroyed();
gameStatus.AddToScore();
Destroy(gameObject);
}
}
And on level 1 everything works fine, but when the game goes to the next level this happens:
Player score stops updating.
If I use Debug.Log(currentScore); in GameStatus.cs I can see that this variable doesn't change when player breaks blocks, but if use Debug.Log(gameStatus.currentScore); in Block.cs then I can see that this variable is getting updated.
Debug.Log(FindObjectsOfType().Length); shows that there is one GameStatus object in the first level and two objects in the next levels, although I can't see the second one GameStatus in hierarchy.
So my question is - what's wrong and how to fix it?
If you use singleton, there is no point to make
currentScore
static variable, just make it
public int currentScore;
Also in your block cs you can just call
GameStatus.instance.AddToScore();
No need to make reference at start

Add float number to another script, c# unity [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
I need help, i'am trying to add float number from a script to another script but it does not work. I'am new to c# and coding in general if somebody code fix the script and explained whats wrong with this i would be very thankful. This is the error i am getting.
"NullReferenceException: Object reference not set to an instance of an object
Resources.Die () (at Assets/Resources.cs:42)
Resources.Update () (at Assets/Resources.cs:22)"
Here is my scripts:
1st
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour {
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Texture stoneIcon;
public Texture woodIcon;
void Start ()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update ()
{
Die();
}
public void OnMouseOver()
{
if(Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if(currentHealth <= 0)
{
Destroy(gameObject);
Inventory inventory = GetComponent<Inventory>();
inventory.ResourceStone = inventory.ResourceStone + 1;
}
}
}
2nd
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour {
public float ResourceStone;
// Use this for initialization
void Start ()
{
ResourceStone = 0;
}
// Update is called once per frame
void Update () {
}
}
By looking at your code i think you never defined the inventory instance for your "resources" script. If you are using a getcomponent both the resources and the inventory script must be on the same gameobject to be found.
If what you want requires both scripts to be on other gameobjects you need a reference to the inventory in your resources script.
You can do this several way (like making a static reference and refering to it or defining inventory as a public variable and then adding the inventory reference in the unity editor)
This is how the first case would look:
First Script -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public static Inventory instance;
private void Awake()
{
instance = this;
}
public float ResourceStone;
// Use this for initialization
void Start()
{
ResourceStone = 0;
}
}
Second Script -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour
{
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Texture stoneIcon;
public Texture woodIcon;
void Start()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update()
{
Die();
}
public void OnMouseOver()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if (currentHealth <= 0)
{
Destroy(gameObject);
Inventory.instance.ResourceStone++;
}
}
}
This is how the code would look if you did the second one:
first script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public float ResourceStone;
// Use this for initialization
void Start()
{
ResourceStone = 0;
}
// Update is called once per frame
void Update()
{
}
}
second script-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour
{
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Inventory inventory;
public Texture stoneIcon;
public Texture woodIcon;
void Start()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update()
{
Die();
}
public void OnMouseOver()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if (currentHealth <= 0)
{
Destroy(gameObject);
inventory.ResourceStone++;
}
}
}
Just take in account two things to decide if you will use the first or the second one. The first one is a static reference, that means that you can't make more that one inventory. In the second one you need to manually drag the reference in the editor. Just in case you don't know, writing ++ after an integer does the same as integer = integer + 1;
EDIT: There, that's better looking :D

Unity cant find the other script NullReferenceException: Object reference not set to an instance of an object [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 5 years ago.
So my TowerNode script cant find the Shop script and active or disable it for some reason it just cant find it so it give me a "NullReferenceException: Object reference not set to an instance of an object
TowerNode.OnMouseDown () (at Assets/Scripts/TowerNode.cs:46)"
its cant make the Shop.Enable method on line 46
this is the TowerNode script
public bool IsShopOpen = false;
//Z position
public Vector3 positionOffSet;
//colors
public Color hoverColor;
private Color startColor;
//GameObjects
public GameObject turret;
//shop
public Shop shop;
//renderer!!
private Renderer rend;
//Build Manager
BuildManager buildManager;
void Start()
{
rend=GetComponent<Renderer>();
startColor = rend.material.color;
buildManager = BuildManager.instance;
shop = GetComponent<Shop>();
GameObject.Find("Shop");
}
//When mouse is on the turret node
void OnMouseDown()
{
bool IsShopOpen = true;
if (IsShopOpen == true)
{
shop.Enable();
}
if (EventSystem.current.IsPointerOverGameObject())
{
return;
}
if (!buildManager.CanBuild)
{
return;
}
if (turret != null)
{
Debug.Log("Cant Build Here!!!");
return;
}
buildManager.BuildTurretOn(this);
}
public Vector3 GetBuildPosition()
{
return transform.position + positionOffSet;
}
//when mouse get into the node space
void OnMouseEnter()
{
rend.material.color = hoverColor;
if (EventSystem.current.IsPointerOverGameObject())
{
return;
}
if (!buildManager.CanBuild)
{
return;
}
}
//when mouse exit the node space
void OnMouseExit()
{
rend.material.color = startColor;
}}
And this is the Shop script:
using UnityEngine;
using UnityEngine.UI;
public class Shop : MonoBehaviour
{
public TurretBlueprint Archery;
public TurretBlueprint Treb;
public TurretBlueprint Workamp;
public TurretBlueprint Barracks;
public Button Archeryy;
public Button Trebb;
public Button WorkCampp;
public Button Barrackss;
BuildManager buildManager;
void Start()
{
buildManager = BuildManager.instance;
disableAllButtons();
//Enable();
}
public void SelectArchery()
{
buildManager.SelectTurretToBuild(Archery);
Debug.Log("archery!!!!");
}
public void SelectTreb()
{
buildManager.SelectTurretToBuild(Treb);
Debug.Log("Treb!!!!");
}
public void SelectWorkamp()
{
buildManager.SelectTurretToBuild(Workamp);
Debug.Log("Work Camp!!!!");
}
public void SelectBarracks()
{
buildManager.SelectTurretToBuild(Barracks);
Debug.Log("Barracks!!!!");
}
public void Enable()
{
Archeryy.gameObject.SetActive(true);
Trebb.gameObject.SetActive(true);
WorkCampp.gameObject.SetActive(true);
Barrackss.gameObject.SetActive(true);
}
public void disableAllButtons()
{
Archeryy.gameObject.SetActive(false);
Trebb.gameObject.SetActive(false);
WorkCampp.gameObject.SetActive(false);
Barrackss.gameObject.SetActive(false);
}}
shop = GetComponent<Shop>();
GameObject.Find("Shop");
I'm assuming the Shop script resides on the GameObject named Shop, and not the TowerNode GameObject, which would mean you should get the Shop script from that gameobject like so:
shop = GameObject.Find("Shop").GetComponent<Shop>();

Categories

Resources