I am trying to show interstitial ads when the player clicks on specific button (hint button), but Unity is giving me this error:
> NullReferenceException: Object reference not set to an instance of an
> object ButtonManager.Hint()...
This is the code for showing the ad:
public class ButtonManager : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void Reload()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
public void Home()
{
SceneManager.LoadScene("MainMenu");
}
int contc;
public void Play()
{
SceneManager.LoadScene("LevelMenu");
}
public void Hint()
{
FindObjectOfType<AdMobManager>().Hint = true;
FindObjectOfType<AdMobManager>().showInterstitial();
}
Any idea how can I get around this problem?
That is a C# error, you are trying to use a null Object.
I think the problem is:
FindObjectOfType()
Check if you really get any object with that Find.
Related
I am building out a Zelda game and I have ran into an issue -
public void UpdateCoins()
{
Debug.Log(GameManager.instance.currCoins);
//coinsText.text = "Coins " + GameManager.instance.currCoins;
}
That works as expected -
But when I do this...
public void UpdateCoins()
{
Debug.Log(GameManager.instance.currCoins);
coinsText.text = "Coins " + GameManager.instance.currCoins;
}
I receive an Object Reference not set to an instance of the object error.
As you can see it is set. Here is my simple GameManager script
public static GameManager instance;
public int currCoins;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void GetCoins(int coinsToAdd)
{
currCoins += coinsToAdd;
UIManager.instance.UpdateCoins();
}
}
Any thoughts on why this isn't working the way it should?
Thanks!
Try add more logs
Either the coinsText or the coinsText.text is null, so what I would do is:
Debug.Log(coinsText);
if(coinsText != null) Debug.Log(coinsText.text);
I'm sure you'll make a great Zelda game but let's fix your issue here first , you are trying to access to an int GameManager.instance.currCoins
but returns null simply because the currCoins you're using is not even to been set to zero.
Also as a tip if you are going to use an int in a string text or something always use ToString() :
coinsText.text = "Coins " + GameManager.instance.currCoins.ToString();
Number 2 issue here , your use of singleton it should be like this
public static GameManager instance;
public void Awake()
{
if(instance == null){
instace = this;
}else
{
DontDestroyOnLoad(gameObject);
}
}
Last issue that may not be one now but in the future change the name of this method now while you still can public void GetCoins(int coinsToAdd)to something like AddCoins(int coinsToAdd)
I added Unity Ads to my project.
At the first run at all works good and it show that an ad will show, but when I hit play the second time it give me this error
MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
This is my script for the ads :
public class Monetization : MonoBehaviour, IUnityAdsListener
{
string GooglePlay_ID = "****";
bool GameMode = true;
string myPlacementId = "rewardedVideo";
void Start()
{
Advertisement.AddListener(this);
Advertisement.Initialize(GooglePlay_ID, GameMode);
}
public void ShowRewardedVideo()
{
// Check if UnityAds ready before calling Show method:
if (Advertisement.IsReady(myPlacementId))
{
Advertisement.Show(myPlacementId);
}
else
{
Debug.Log("Rewarded video is not ready at the moment! Please try again later!");
}
}
// Implement IUnityAdsListener interface methods:
public void OnUnityAdsDidFinish(string placementId, ShowResult showResult)
{
// Define conditional logic for each ad completion status:
if (showResult == ShowResult.Finished)
{
// Reward the user for watching the ad to completion.
SceneManager.LoadScene(4);
}
else if (showResult == ShowResult.Skipped)
{
// Do not reward the user for skipping the ad.
}
else if (showResult == ShowResult.Failed)
{
Debug.LogWarning("The ad did not finish due to an error.");
}
}
public void OnUnityAdsReady(string placementId)
{
// If the ready Placement is rewarded, show the ad:
if (placementId == myPlacementId)
{
// Optional actions to take when the placement becomes ready(For example, enable the rewarded ads button)
}
}
public void OnUnityAdsDidError(string message)
{
// Log the error.
}
public void OnUnityAdsDidStart(string placementId)
{
// Optional actions to take when the end-users triggers an ad.
}
}
When you load a new scene, the game objects in the previous scene will be destroyed. To prevent this add the following function in your Monetization script.
void Awake() {
DontDestroyOnLoad(this.gameObject);
}
I have an empty GameObject on my Canvas used to display an ad menu, which I have attached to a separate script (not on the menu itself) in a public variable through the inspector.
I am setting it inactive in a script using adMenu.SetActive(false), which works on the first playthrough of my game. However, when I restart the scene through a button in my scene, the menu loses its reference to the same GameObject in the inspector, and I receive this error:
MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
This has never happened to me with other GameObjects initialized in similar ways after a scene reload.
Additional details:
GameObject.Find() can retrieve the GameObject using its name from within the same script
DontDestroyOnLoad() is not used anywhere on the script or on the GameObject it's attached to
Code:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Advertisements;
using MEC;
public class AdManager : MonoBehaviour, IUnityAdsListener
{
internal static AdManager instance;
private static bool isInitialized = false;
public GameObject adMenu;
private string placement = "rewardedVideo";
void Start()
{
instance = this;
if (!isInitialized)
{
isInitialized = true;
Advertisement.AddListener(this);
Advertisement.Initialize(Constants.appleGameId, true);
}
}
IEnumerator<float> ShowAd()
{
if (!Advertisement.IsReady())
{
yield return Timing.WaitForOneFrame;
}
Advertisement.Show(placement);
}
public void CloseAdMenu()
{
Debug.Log("Is adMenu null: " + (adMenu == null)); // Returns false on first playthrough only
adMenu.SetActive(false);
}
public void OnUnityAdsDidFinish(string placementId, ShowResult showResult)
{
if (showResult == ShowResult.Finished)
{
CloseAdMenu();
}
}
public void OnUnityAdsReady(string placementId)
{
// throw new System.NotImplementedException();
}
public void OnUnityAdsDidError(string message)
{
// throw new System.NotImplementedException();
}
public void OnUnityAdsDidStart(string placementId)
{
// throw new System.NotImplementedException();
}
}
What happens has nothing to do with your menu object nor the static Instance.
The issue is the callback of
public void OnUnityAdsDidFinish(string placementId, ShowResult showResult)
since you registered the instance via
Advertisement.AddListener(this);
but this instance will be Destroyer after the scene was changed.
As shown in the examples you should do
private void OnDestroy()
{
Advertisement.RemoveListener(this);
}
On your restart method, you should re-activate the button with adMenu.SetActive(true), if not, when you call the scene again, adMenu GameObject is disabled, so you can't access the GameObject.
Maybe you can add a method in your AdManager like:
public void OpenAdMenu()
{
adMenu.SetActive(true);
}
and call it on AdManager.Start()
I'm confused about finding reference GameObject but different Scene and set the onclick when difference scene, so I have GameManager who manage all but available only on the Main menu. So I decide to make Dontdestroyonload, the issue start at this, so when I play to the MainGame Scene, the field of GameManager at inspector will find, but I can't drag n drop different scene, right? That confuses me.
And if the GameManager at the MainMenu scene, the question is how to drag n drop at the onClick event, like I want pause button active or something else in the game.
]3
I tried with onLloadscene(scene s, Mode mode), but nothing happens, and here the scrip for the GameManager. :
public static GameManager gameManager;
[Header("Main Menu panels")]
public GameObject startPanel;
public GameObject settingPanel;
public GameObject levelPanel;
[Header("InGame Panels")]
#region Panel
public GameObject pausePanel;
public GameObject ObjectivePanel;
public GameObject shopPanel;
private int click = 0;
[Header("Int Tweaks")]
public int indexLevel;
public int onlevel;
public bool isPaused;
_levelSelect LevelSelect;
public static GameManager Instance { set; get; }
public int levelindexPlayerPrefs;
private void Awake()
{
if (gameManager != null)
{
Instance = this;
Destroy(gameObject);
}
else
{
DontDestroyOnLoad(gameObject);
}
}
void Start()
{
LevelSelect = FindObjectOfType<_levelSelect>();
OnStart();
onlevel = int.Parse(LevelSelect.levelIndex) + 1;
indexLevel = int.Parse(LevelSelect.levelIndex);
getPlayerData();
}
// Update is called once per frame
void Update()
{
ExitApp();
}
public void OnStart()
{
startPanel.SetActive(true);
settingPanel.SetActive(false);
levelPanel.SetActive(false);
}
#region Buttons
public void startbutton()
{
levelPanel.SetActive(true);
startPanel.SetActive(false);
settingPanel.SetActive(false);
}
public void backButtonMainMenu()
{
levelPanel.SetActive(false);
startPanel.SetActive(true);
settingPanel.SetActive(false);
}
public void settingbutton()
{
levelPanel.SetActive(false);
startPanel.SetActive(false);
settingPanel.SetActive(true);
}
public void PauseButton()
{
Time.timeScale = 0f;
pausePanel.SetActive(true);
ObjectivePanel.SetActive(false);
}
public void Resume()
{
Time.timeScale = 1f;
}
#endregion
public void ExitApp()
{
if (Input.GetKey(KeyCode.Escape))
{
click++;
StartCoroutine(ClickTime());
if (click>1)
{
print("Exit Game");
Application.Quit();
}
}
}
IEnumerator ClickTime()
{
yield return new WaitForSeconds(0.5f);
click = 0;
}
public void getPlayerData()
{
levelindexPlayerPrefs = PlayerPrefs.GetInt("LevelIndex", 0);
}
public void updateLevel(int Index)
{
if (levelindexPlayerPrefs < Index)
{
PlayerPrefs.SetInt("LevelIndex", Index);
levelindexPlayerPrefs = PlayerPrefs.GetInt("LevelIndex");
}
}
#region onloadedScenePickRefferences
private void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
pausePanel = GameObject.FindGameObjectWithTag("PausePanel");
ObjectivePanel = GameObject.FindGameObjectWithTag("ObjectivePanel");
}
#endregion
//public IEnumerator EndChapter()
//{
// updateLevel(indexLevel + 1);
// getPlayerData();
//}
Here is what I would probably do:
Have a static class for storing and sharing all your references. It doesn't have to be in any scene but simply "lives" in the assets:
public static class GlobalReferences
{
// as example just for one reference but you can implement the rest equally yourself
// here this class actually stores the reference
private static GameObject startPanel;
// A public property in order to add some logic
// other classes will always access and set the value through this property
public static GameObject StartPanel
{
get
{
// if the reference exists return it right away
if(startPanel) return startPanel;
// as a fallback try to find it
startPanel = GameObject.FindGameObjectWithTag("StartPanel");
// ofcourse it might still fail when you simply try to access it
// in a moment it doesn't exist yet
return startPanel;
}
set
{
startPanel = value;
// invoke an event to tell all listeners that the startPanel
// was just assigned
OnStartPanelReady?.Invoke();
}
}
// An event you will invoke after assigning a value making sure that
// other scripts only access this value after it has been set
// you can even directly pass the reference in
public static event Action<GameObject> OnStartPanelReady;
}
So now in your component(s) that is(are) in the new loaded scene you assign the value as early as possible (Awake). Here you can already store it via the Inspector since it is a scene reference:
public class ExampleSetter : MonoBehaviour
{
// already reference it via the Inspector
[SerializeField] private GameObject startPanel;
private void Awake()
{
// as a fallback
if(!startPanel) startPanel = GameObject.FindObjectWithTag("startPanel");
// assign it to the global class
GlobalReferences.StartPanel = startPanel;
}
}
And in other scenes that where already loaded before you add a listener so they do their stuff as soon as the other scene is ready:
public class ExampleConsumer : MonoBehaviour
{
[Header("Debug")]
[SerializeField] private GameObject startPanel;
private void Awake()
{
// Try to get the reference
startPanel = GlobalReferences.StartPanel;
// if this failed then wait until it is ready
if(!startPanel)
{
// it is save to remove callbacks even if not added yet
// makes sure a listener is always only added once
GlobalReferences.OnStartPanelReady -= OnStartPanelReady;
GlobalReferences.OnStartPanelReady += OnStartPanelReady;
}
// otherwise already do what you want
else
{
OnStartPanelReady(startPanel);
}
}
private void OnDestroy()
{
// always make sure to clean up callbacks when not needed anymore!
GlobalReferences.OnStartPanelReady -= OnStartPanelReady;
}
private void OnStartPanelReady(GameObject newStartPanel)
{
startPanel = newStartPanel;
// always make sure to clean up callbacks when not needed anymore!
GlobalReferences.OnStartPanelReady -= OnStartPanelReady;
// NOTE: It is possible that at this point it is null anyway if another
// class has set this actively to null ;)
if(startPanel)
{
// Now do something with the startPanel
}
}
}
The other way round when you need a reference in the new loaded Scene form the main scene ... it should already be set since the mainscene was loaded first and has already assigned its according references.
Now you can either go for this static class or simply implement the same logic for each reference that needs to be shared directly in an according component where you reference them via drag&drop .. it makes no difference since anyway you will use static fields and events that are not bound to any instance but the type(s) itself.
i have a a problem to active UI from prefabs when click on object using OnMouseDown code
public class TreeManager : MonoBehaviour {
public GameObject FuncUI;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnMouseDown()
{
if (FuncUI.activeInHierarchy == false)
{
FuncUI.SetActive (true);
}
else
{
FuncUI.SetActive (false);
}
}
public void ExitOn()
{
Application.Quit ();
}
}
this OnMouseDown code is working if both object and gameobject UI is on hierarchy. but it not work if both i use from prefabs.. what i need to change so i can make it work for prefabs? my function UI is from canvas. when i click on the object, the FuncUI will appear on screen. this code i put inside the object that i want to click to appear FuncUI