I’m having a problem using a public static variable in a UI Canvas.
I have a Game Object that holds the player score. When time is up, I either instantiate a wining canvas or a loose canvas. But when I try to access the player score in a button in the canvas, it says that the object is null.
using UnityEngine;
using System.Collections;
using System;
public class AdsButtonController : MonoBehaviour
{
private DateTime thisTime;
private DateTime nextTimeGiveBonus;
// Use this for initialization
void Awake ()
{
nextTimeGiveBonus = AdsAvailabilityControl.adsvailabilityControl.nextTimeToGiveExtraBonus;
}
void Start ()
{
}
// Update is called once per frame
void Update ()
{
thisTime = System.DateTime.Now;
if (thisTime >= nextTimeGiveBonus)
{
gameObject.SetActive (true);
} else
{
gameObject.SetActive (false);
}
}
}
This script is attached to the button. But when the canvas is instantiated it says that AdsAvailabilityControl is null. But it is in the Hierarchy.
public class AdsAvailabilityControl : MonoBehaviour
{
public static AdsAvailabilityControl adsvailabilityControl = null; // Instancia do script
public DateTime lastTimeAddedBonus; // Variavel indica a ultima vez que o jogador ganhou extra bonus, para evitar de dar
// mais de um extra bonus a cada 30 min
public Queue<DateTime> addDateQueue = new Queue<DateTime>(); // Varivel usada para guardar as datas dos bonus extras
public DateTime nextTimeToGiveExtraBonus; // Determina a hora para o proximo extra bonus
void Awake()
{
if (adsvailabilityControl == null) // Checando se o objeto (BonusManager) ja existe
{
DontDestroyOnLoad (gameObject); // Se nao existir, faz com que esse nao seja destruido ao se trocar de cena
adsvailabilityControl = this; // Seta esse objeto na instancia do script
LoadAddAvailabilityData();
EventManager.AddHandler (EVENT.OnWatchedVideo, UpdateAdsAvailability);
} else if (adsvailabilityControl != this)
{
Destroy(gameObject); // Se ja existir esse objeto entao ele se auto destroi
}
}
1.) Order of initialization. You might be requesting the singleton-like instance before Awake is called.
Try this pattern instead:
public class MySingletonClass : MonoBehaviour
{
public static MySingletonClass instance
{
get
{
if(_instance == null)
{
_instance = (MySingletonClass)FindObjectOfType(typeof(MySingletonClass));
DontDestroyOnLoad(_instance.gameObject);
}
return _instance;
}
}
private static MySingletonClass _instance;
void Awake()
{
if (_instance != null && _instance != this)
{
Debug.LogError("Singleton already initialized.");
Destroy(this.gameObject);
}
}
}
2.) There might be another instance of the single-like class. Maybe you are instantiating a second one at runtime and referencing the wrong one. Again, you can see if it works better with the lazy-initialization I show in the code sample.
A typo. I meant “_instance” There might be others, I don’t have an IDE to check right now and you might want to add in additional checks like what to do when there is not instance to be found or find all objects of type and see if the array returns more than one and things like that to make it more safe. Generally, you want to try to code safe by thinking about everything that can go wrong and at least log an error if it happens. That way you will probably find out what your specific problem is about.
That really isn’t the case. What is probably happening, as @Xarbrough_1 mentioned, is an order of initialization problem.
You setup your nextTimeGiveBonus var in Awake(), but you also only setup your AdsAvailabilityControl static variable in its Awake(), so what is happening is that AdsButtonController initializes BEFORE AdsAvailabilityControl, and at that point the variable is still null.
You can fix this simply by moving the code in AdsButtonController from Awake() to Start(). In general, you want Awake() to initialize just the local class, and not access anything else. Further initialization, especially ones that require access of other objects, is better done in Start(), which will guarantee that accessed objects are initialized, in your case, AdsAvailabilityControl static var.