Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Chasing down yet another NullReferenceException

Discussion in 'Getting Started' started by Rasborealis, Jul 24, 2023.

  1. Rasborealis

    Rasborealis

    Joined:
    Jan 13, 2023
    Posts:
    7
    I thought I was finally getting the hang of figuring these out, but this one is making me scratch my head, so I'd appreciate a bit of help. (Sidenote: constructive criticism on my code in general is appreciated as well, if any part of it stands out as particularly cringy to you. I know I have a lot to learn.) I'm also sorry this is such a long post, I tried to cut down the code to only the relevant parts, but since I don't know what the problem is, I was worried about accidentally cutting too much.

    I'm working on a "New Day" button for the player to finish the current game day, which should re-activate some daily task buttons and also reset the player's energy score to its default. The second of those is throwing the error. I'm getting the usual
    NullReferenceException: Object reference not set to an instance of an object
    TaskScript.newDay () (at Assets/Scripts/TaskScript.cs:25)

    Here are the relevant parts of TaskScript:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5. using TMPro;
    6.  
    7. public class TaskScript : MonoBehaviour
    8. {
    9.     public LogicManager logicManager;
    10.     public DemoScript demoScript;
    11.     public InventoryManager inventoryManager;
    12.     public GameObject dailyButtonGroup;
    13.     public CurrencyScript currencyScript;  
    14.     public TMP_Text dayCounter;
    15.     public int dayNum;
    16.  
    17.     public void newDay()
    18.     {
    19.         // increase day count by 1
    20.         dayNum = ReadStringInput(dayCounter.text);
    21.         dayNum++;
    22.         dayCounter.text = dayNum.ToString();
    23.  
    24.         // reset energy to max
    25.         currencyScript.resetEnergy(); //this is the problem line, Object reference not set to an instance of an object
    26.     }
    What has me confused is that the next function in the script has no issues at all when it accesses CurrencyScript functions:

    Code (CSharp):
    1. public void fetchWater()
    2.     {
    3.         // add water to inventory
    4.         demoScript = dailyButtonGroup.GetComponent<DemoScript>();
    5.         demoScript.PickupItem(11, 1);
    6.  
    7.         // subtract 1 energy
    8.         Debug.Log("Energy level is " + currencyScript.energyInt); // this does give me the correct number
    9.         currencyScript.subtractEnergy(1);
    10.         Debug.Log("Energy Level now is " + currencyScript.getEnergy()); // this is also correct in the console, one less than the previous one, obviously.
    11. }
    12.  
    So naturally, I started looking through CurrencyScript for the issue. Here are the relevant functions of that:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using TMPro;
    6.  
    7. public class CurrencyScript : MonoBehaviour
    8. {
    9.     public PlayerManager playerManager;
    10.     public Character mainChar;
    11.     public TMP_Text energyText;
    12.     public int energyInt;
    13.  
    14.  
    15.     public void resetEnergy()
    16.     {
    17.         int.TryParse(energyText.text, out energyInt);
    18.         energyInt = playerManager.getStat(4);
    19.  
    20.         energyText.text = energyInt.ToString();
    21.     }
    22.     public void subtractEnergy(int amount)
    23.     {
    24.         int.TryParse(energyText.text, out energyInt);
    25.         energyInt = energyInt - amount;
    26.         energyText.text = energyInt.ToString();
    27.     }
    28.     public int getEnergy()
    29.     {
    30.         int.TryParse(energyText.text, out energyInt);
    31.         return energyInt;
    32.     }
    33.  
    And then the "PlayerManager" script because that's the only relevant difference I could see:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerManager : MonoBehaviour
    6. {
    7.  
    8.     public Character mainChar;
    9.  
    10.     public int getStat(int statDef)
    11.     {
    12.         return mainChar.stats[statDef];
    13.     }
    14.     public void setStat(int statDef, int i)
    15.     {
    16.         mainChar.stats[statDef] = i;
    17.     }
    18. }
    19.  
    The stat array seems set up properly, I've had no trouble assigning values to it. So as of right now, I'm pretty stuck and would appreciate help or advice.

    Thank you in advance.
     
  2. AngryProgrammer

    AngryProgrammer

    Joined:
    Jun 4, 2019
    Posts:
    431
    NullReferenceException is one of the most common errors that you must learn to handle by yourself. You read the log at this stage so it's good, but you start digging deeper than you need.

    Code (CSharp):
    1.     public void newDay()
    2.     {
    3.         // increase day count by 1
    4.         dayNum = ReadStringInput(dayCounter.text);
    5.         dayNum++;
    6.         dayCounter.text = dayNum.ToString();
    7.         // reset energy to max
    8.         if(currentScript == null)
    9.         {
    10.             Debug.Log("It's null!");
    11.         }
    12.         currencyScript.resetEnergy(); //this is the problem line, Object reference not set to an instance of an object
    13.     }
    I added a simple if statement, if it's null then it's null. There is no point to go deeper. And if it's null here then it's about how you use TaskScript, do you reload the scene, create its copy, etc. Maybe scripts are making racing who gets to currencyScript first and one set null before you use it second. Maybe CurrencyScript you are referring to gets destroyed at this point?
     
  3. Rasborealis

    Rasborealis

    Joined:
    Jan 13, 2023
    Posts:
    7
    Thanks for replying. I was kinda wondering whether I was going down a rabbit hole trying to figure this out. I hope you don't mind if I ask some questions.

    I tried to add your if statement, but it did not trigger for me when running the code, I just got the original NullReferenceException again. Am I missing something obvious?

    The thing that's stumping me is that there isn't really anything else going on while this bit of code runs. The OnClick Events for the button that triggers it only re-enable a couple of other buttons otherwise, and newDay is the only method that is called by it apart from that. CurrencyScript thus far is only used for subtracting and resetting energy, but this button doesn't have an energy cost, so I'm not sure what else could be interfering. Do you have any other recommendations for troubleshooting this?
     
  4. AngryProgrammer

    AngryProgrammer

    Joined:
    Jun 4, 2019
    Posts:
    431
    If the console didn't return anything then we can dig now. You need to profile somehow how code is executed, you can add more Debug.Log (at the beginning or end of functions, or its important parts), and you can also wrap code in functions in try-catch.

    For educational purposes or if it's really hard to understand the flow of code I just take pen and paper and do a simple sequence diagram and compare it with code fragments.
     
  5. Rasborealis

    Rasborealis

    Joined:
    Jan 13, 2023
    Posts:
    7
    I'll do that. Pen and paper actually sounds like a good idea, since I often have trouble keeping the connections straight in my head. Hopefully it'll lead me somewhere.

    Thanks again, I appreciate you taking the time to give me advice.
     
  6. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    521
    This is important as that debug line should (more or less) be output. I would output the result rather than just when it is null. Debug.Log(currentScript == null ? "is null" : "not null");

    You might consider adding Start methods as well again just to confirm the order things are starting.
     
    AngryProgrammer likes this.
  7. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    521
    As for constructive criticism... you aren't quite following the naming convention for public methods. Capitalize the first letter NewDay, ResetEnergy, GetStat, etc.
     
  8. Rasborealis

    Rasborealis

    Joined:
    Jan 13, 2023
    Posts:
    7
    Thank you for the extra advice, I appreciate it. Will fix my lack of first letter caps and try out the altered Debug.Log. I've been working on a few other things this week since this particular problem was getting frustrating, but I'm about to give it a fresh try.