Error in buying button

Hi,

I have the next error: NullReferenceException: Object Reference not set to an instance of object. It happen when I click a button for buy a object in the game. You can see it in the next image:

But I have some doubts when implementing the code, for example. My code is:

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

public class TradeCupcakeTowers_Buying : TradeCupcakeTowers {

    // Public variable to identify wich tower this script is selling.
    // Ideally, you could have many instances of this script seling different cupcake towers,
    // and the tower is specified in the Inspector.
    public GameObject cupcakeTowerPrefab;

    public override void OnPointerClick(PointerEventData eventData)
    {
        //Retrieve form the prefab which is its initial cost
        int price = cupcakeTowerPrefab.GetComponent<CupcakeTowerScript>().initialCost;

        // check if the player can afford to buy the tower
        if (price <= sugarMeter.getSugarAmount())
        {
            // Payment success, and the cost is removed from the player's sugar
            sugarMeter.ChangeSuger(-price);
            // A new cupcake tower is created
            GameObject newTower = Instantiate(cupcakeTowerPrefab);
            // The new cupcake tower is also assigned as the current selection
            currentActiveTower = newTower.GetComponent<CupcakeTowerScript>();
        }
    }

    // Use this for initialization
    void Start () {

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

But, Visual Studio advises me to change my code in public override void OnPointerClick(PointerEventData eventData), calling a new method. In this new method perform the purchase actions. You can see it below:

public override void OnPointerClick(PointerEventData eventData)
    {
        //Retrieve form the prefab which is its initial cost
        int price = cupcakeTowerPrefab.GetComponent<CupcakeTowerScript>().initialCost;

        // check if the player can afford to buy the tower
        NewMethod(price);
    }

    private void NewMethod(int price)
    {
        if (price <= sugarMeter.getSugarAmount())
        {
            // Payment success, and the cost is removed from the player's sugar
            sugarMeter.ChangeSuger(-price);
            // A new cupcake tower is created
            GameObject newTower = Instantiate(cupcakeTowerPrefab);
            // The new cupcake tower is also assigned as the current selection
            currentActiveTower = newTower.GetComponent<CupcakeTowerScript>();
        }
    }

In any case, the error mentioned at the beginning persists.

What could I be doing wrong?

Thanks for your comments!
Regards!

So, does the console tell you on which line the error occurs? If so, did you check that line of code & then try to figure out which “possible” variable was null (if there is more than one)?
:slight_smile:

Hi, methos5k! Me again :eyes:

Ok, it have 2 steps


First, when I apply the changes suggest by Visual Studio:

this is:

 public override void OnPointerClick(PointerEventData eventData)
    {
        //Retrieve form the prefab which is its initial cost
        int price = cupcakeTowerPrefab.GetComponent<CupcakeTowerScript>().initialCost;

        // check if the player can afford to buy the tower
        NewMethod(price);
    }

    private void NewMethod(int price)
    {
        NewMethod1(price);
    }

    private void NewMethod1(int price)
    {
        if (price <= sugarMeter.getSugarAmount())
        {
            // Payment success, and the cost is removed from the player's sugar
            sugarMeter.ChangeSuger(-price);
            // A new cupcake tower is created
            GameObject newTower = Instantiate(cupcakeTowerPrefab);
            // The new cupcake tower is also assigned as the current selection
            currentActiveTower = newTower.GetComponent<CupcakeTowerScript>();
        }
    }

Now, I play the game and it show the next:

NullReferenceException: Object reference not set to an instance of an object
TradeCupcakeTowers_Buying.NewMethod1 (Int32 price) (at Assets/Scripts/UI_Scripts/TradeCupcakeTowers_Buying.cs:29)
TradeCupcakeTowers_Buying.NewMethod (Int32 price) (at Assets/Scripts/UI_Scripts/TradeCupcakeTowers_Buying.cs:24)
TradeCupcakeTowers_Buying.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Assets/Scripts/UI_Scripts/TradeCupcakeTowers_Buying.cs:19)
UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:50)
UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:261)
UnityEngine.EventSystems.EventSystem:Update()

Right, I’m not sure to which line that is referring because your post’s lines do not match the lines from the error (on my end). Did you try to look at the line and see what could possibly be null?

Hi!

Sorry, coming back from work


I apply some debug.logs:

public override void OnPointerClick(PointerEventData eventData)
    {
        //Retrieve form the prefab which is its initial cost
        int price = cupcakeTowerPrefab.GetComponent<CupcakeTowerScript>().initialCost;

        Debug.Log("Error1: " + price);


        // check if the player can afford to buy the tower
        if (price <= sugarMeter.getSugarAmount())
        {
            Debug.Log("Error2: " + sugarMeter.getSugarAmount());
            // Payment success, and the cost is removed from the player's sugar
            sugarMeter.ChangeSuger(-price);
            // A new cupcake tower is created
            GameObject newTower = Instantiate(cupcakeTowerPrefab);
            // The new cupcake tower is also assigned as the current selection
            currentActiveTower = newTower.GetComponent<CupcakeTowerScript>();
        }
        else {
            Debug.Log("here!");

        }
    }

var price return value, but sugarMeter.getSugarAmount() not


Error1: 10
UnityEngine.Debug:Log(Object)
TradeCupcakeTowers_Buying:OnPointerClick(PointerEventData) (at Assets/Scripts/UI_Scripts/TradeCupcakeTowers_Buying.cs:18)
UnityEngine.EventSystems.EventSystem:Update()

The script never enters the if statement


I think the problem is that I do not have money to buy, well, my player. This has not been established yet. I believe.

Can you confirm that sugarMeter is not null?

Mmmm
 maybe it is the error:

In my canvas I have the sugar meter text as the next image:

and in the example is:

Do you think that could be that?

That’s not exactly what I meant. In your OnPointerClick, the variable ‘sugarMeter’ in there - is that assigned properly in that script?

This is the script for sugar meter:

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

public class Sugar_meterScript : MonoBehaviour {

    private Text sugarMeter; // Referencia la componente de texto
    private int sugar; // Cantidad de azucar que el player posee

    // Use this for initialization
    void Start () {
        // Get the reference to the Sugar_Meter_Text
        sugarMeter = GetComponentInChildren<Text>();
        // Update the sugar meter graphics
        updateSugarMeter();
       
    }
   
    // Update is called once per frame
    void Update () {
       
    }

    // FunciĂłn para incrementar o decrementar la cantidad de azĂșcar
    public void ChangeSuger(int value) {
        // Incrementa oa decrementa, si el valor es negativo, la cantidad de ĂĄzĂșcar
        sugar += value;
        // Checa si la cantidad de azucar es negativa, si es asĂ­ la establece en cero.
        if (sugar < 0) {
            sugar = 0;
        }
        // Update sugar meter graphic
        updateSugarMeter();
    }

    // FunciĂłn para regresar la cantidad de azĂșcar
    public int getSugarAmount() {
        return sugar;
    }

    // funciĂłn para actualizar Sugar Meter graphic
    void updateSugarMeter() {
        // Assign the amount of sugar converted to a string to the text in the sugar meter
        sugarMeter.text = sugar.ToString();
    }
}

So, the fact that the text “1235” is not shown does not imply that it is not working correctly?

Okay, sometimes it’s hard to follow screenshots. I noticed your font size is 100 . Do you think you can’t see it because it doesn’t fit maybe? It should be showing that value in the inspector, while not playing, but when the game starts, it would probably say ‘0’ , since you have not set any value (other than the default 0) to the ‘sugar’.

This is what I was asking about – re: the sugarMeter variable from this snippet of your code:

// check if the player can afford to buy the tower
        if (price <= sugarMeter.getSugarAmount())
        {
            Debug.Log("Error2: " + sugarMeter.getSugarAmount());
            // Payment success, and the cost is removed from the player's sugar
            sugarMeter.ChangeSuger(-price);

I thought you were telling me the error was around here? Please correct me if I’ve been mistaken about that for the last while. lol

1 Like

Oh! Sorry, you don’t wrong. My mistake is not explaining myself correctly, u.u

I use the text “Error” only as a info, only I try to get the value from sugarMeter.getSugarAmount() to know if price was doing the evaluation correctly in:

if (price <= sugarMeter.getSugarAmount())

Yep, I have the font in 100 pts because I was testing whether the number was visible or not. Its initial value is 14
 Sorry for not correcting it before taking the screenshot u.u

the inspector show me the line 22 as the error. The line 22 is:

 if (price <= sugarMeter.getSugarAmount())

Okay
 so there are a few things.

  1. at 14pt, can you see the text in the editor while not running (or running)?
  2. you didn’t answer the question as to whether the ‘sugarMeter’ from your post there is assigned (ie: not null)

Can you show that script in its entirety in the thread, if my #2 point doesn’t clear it up for you? :slight_smile:

1 Like
  1. No I can’t see the text at 14, 100 or bigger :confused:
  2. If I print sugarMeter value is empty
Value:
UnityEngine.Debug:Log(Object)

Right ,well I knew it was empty, I think b/c you said that was the null error :slight_smile:
What I’m trying to figure out is how were you assigning it? Perhaps you didn’t assign it properly or perhaps not at all? :slight_smile:

As for the text, try to adjust the rect transform size in the editor (like with the rect tool I mean
 just drag it larger until you see the text.)

1 Like

In order to speed things up:

If the script in your first post is complete, post the TradeCupcakeTowers script (which is the base class of your TradeCupcakeTowers_Buying script). This is obviously responsible for resolving the instance of the sugarMeter (of type Sugar_meterScript).

Both are components, the sugarMeter is not exposed (no field for that in the TradeCupcakeTowers’ inspector) so it can only be resolved via code


Now it’s interesting how that is done.
The screenshots show that the TradeCupcakeTower script resides on a GO which is a sibling to the parent of the GO which holds the sugar_meterScript component


That is, if the TradeCupcakeTower script uses anything like GetComponent or GetComponentInChildren, you’re out of luck.
Instead, you’d either

  • search for the GO and get the component,
  • or you use FindObjectOfType
  • or use a singleton
  • OR the most straight-forward solution: expose the sugarMeter to the inspector and drag&drop it.
1 Like

Hi Suddoha, it is the script for TradeCupcakeTowers:

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

public abstract class TradeCupcakeTowers : MonoBehaviour, IPointerClickHandler {

    public abstract void OnPointerClick(PointerEventData eventData);

    // Variable to store the Sugar Meter
    protected static Sugar_meterScript sugarMeter;

    // Variablo to store the current selected tower by the player
    protected static CupcakeTowerScript currentActiveTower;

  

    // Use this for initialization
    void Start () {
        // if the reference to the sugar meter is missing, the scripts get it
        if (sugarMeter == null) {
            sugarMeter = FindObjectOfType<Sugar_meterScript>();
        }
      
    }
  
    // Update is called once per frame
    void Update () {
      
    }

    // Static function that allows other scripts to assign the new/current selected tower
    public static void setActivetower(CupcakeTowerScript cupcakeTower) {
        currentActiveTower = cupcakeTower;
    }
}

I guess, for what you say, the error is somewhere in the code, it has nothing to do with the inspector. I’m reading the book again in case I forgot something 


I hope you figure it out.

Oh okay, the code is fine and would normally work, but it’s a little detail that causes this behaviour:

Your base class (CupcakeTowerScript) uses Start (also Update) and they’re declared as 1) private 2) non-virtual.
Your derived class (CupcakeTowerScript_Buying) uses Start (and also Update) as well.

Behind the scenes, Unity uses something called ‘Reflection’ to figure out these methods (Awake, Start, Update, FixedUpdate 
). What happens is, that Unity will find the Start method (also the Update one) of your derived type and calls this instead of Start of the base class, because there’s no polymorphic behaviour due to missing virtual function calls.

The quick and probably easiest fix for now is, that you remove Start and Update from your Buying script. This helps Unity, it will now find the Start and Update method of the base class and can properly call into it.

If you want to implement further logic within the Buying script’s Start and Update method at a later time (provided you want to use these exact names) you will need the following:

// CupcakeTowerScript
protected virtual void Start() { ... }

// CupcakeTowerScript_Buying
protected override void Start() // optional: protected sealed override void Start()
{
    base.Start();
    // more logic
}

There are 2 more ways to solve this (one of them is horribly wrong), but the above should be well enough.

1 Like

Nice catch, missed that while looking over the script :slight_smile:

1 Like

Oh!! I am happy to learn new things about this every day, things that in the book or a manual I would not easily find :smile:

It working now! I can buy items without errors :smile:

So it is not necessary that in each script the functions Start () and Update () are enabled if they are not required.

Thanks methos5k, Suddoha for your time and patience!! ^^

1 Like