- Home /
Found the answer on my own.
Loading into a scene results in missing script references
So I'm having an issue when I load a scene. I'm using a static instance reference for my game manager, in which I reference certain important scripts that can change depending on the scene. Depending on the scene, some of these references will be empty. The problem is that on loading, I sometimes get missing references to the majority of those scripts, despite the fact that the objects are still present in the scene. And I do mean 'sometimes'. The first 1-2 times a scene is loaded everything works as intended getting the references, but after that they come back as missing on loading a scene. These are the scripts involved in the process: GameManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
//Game Control States
public enum GameState
{
Neutral,
DungeonTravel,
TownTravel,
Combat,
Dialogue
}
//Used when swapping gameState
public GameState currState = GameState.Neutral;
//private GameState prevState = GameState.Neutral;
//Manager Scripts
public ControlManager controlM;
public CameraManager cameraM;
//Mover Scripts
public DungeonMover dungeonMvr;
public TownMover townMvr;
//Map Info
public MapInfo mapInfo;
public static GameManager Instance { get; set; }
// Start is called before the first frame update
void Awake()
{
//Set the reference Instance for the Manager
if (Instance != null && Instance != this)
{
Destroy(this.gameObject);
}
else
{
Instance = this;
}
DontDestroyOnLoad(this.gameObject);
FindMapInfo();
FindReferenceScripts();
ChangeGameState(GameState.Neutral, mapInfo.mapState);
}
// Update is called once per frame
void Update()
{
}
public void FindReferenceScripts()
{
//Managers
if (controlM == null)
{
controlM = this.gameObject.GetComponent<ControlManager>();
Debug.Log("ControlManager found and assigned.");
}
mapInfo.FindReferenceScripts();
}
public void ChangeGameState(GameState currentState, GameState newState)
{
//Processes that run before leaving a certain state
Debug.Log("Running state exit functions...");
switch (currentState)
{
case GameState.Neutral:
break;
case GameState.DungeonTravel:
break;
case GameState.TownTravel:
break;
case GameState.Combat:
break;
case GameState.Dialogue:
break;
}
//Swap GameState
//prevState = currentState;
currState = newState;
//Processes that run after entering a certain state
Debug.Log("Running state entry functions...");
switch (currState)
{
case GameState.Neutral:
Debug.Log("Changing control setup to " + currState);
controlM.LinkControls(currState);
break;
case GameState.DungeonTravel:
Debug.Log("Changing control setup to " + currState);
controlM.LinkControls(currState);
break;
case GameState.TownTravel:
Debug.Log("Changing control setup to " + currState);
controlM.LinkControls(currState);
break;
case GameState.Combat:
Debug.Log("Changing control setup to " + currState);
controlM.LinkControls(currState);
break;
case GameState.Dialogue:
Debug.Log("Changing control setup to " + currState);
controlM.LinkControls(currState);
break;
}
}
public void FindMapInfo()
{
mapInfo = GameObject.Find("MapInfo").GetComponent<MapInfo>();
}
}
MapInfo
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapInfo : MonoBehaviour
{
public GameManager.GameState mapState;
public GameObject playerMover;
private GameManager gameManager = GameManager.Instance;
public void FindReferenceScripts()
{
switch(mapState)
{
case GameManager.GameState.DungeonTravel:
gameManager.dungeonMvr = playerMover.GetComponent<DungeonMover>();
break;
case GameManager.GameState.TownTravel:
gameManager.townMvr = playerMover.GetComponent<TownMover>();
break;
}
gameManager.cameraM = playerMover.GetComponentInChildren<CameraManager>();
if (gameManager.mapInfo == null)
gameManager.mapInfo = this;
}
}
Finally, in a script I use for handling scene loading, this is a function that is set to run when a scene is loaded (SceneManager.sceneLoaded += SceneLoaded; in the script's Awake function):
private void SceneLoaded(Scene scene, LoadSceneMode mode)
{
if(transferPrepared)
{
Debug.Log("Setting mover to starting position...");
TransferRotation();
TransferPosition();
Debug.Log("Finding map info...");
//GameManager.Instance.FindMapInfo();
GameManager.Instance.mapInfo = GameObject.Find("MapInfo").GetComponent<MapInfo>();
Debug.Log("Updating game state...");
GameManager.Instance.ChangeGameState(GameManager.Instance.currState, GameManager.Instance.mapInfo.mapState);
Debug.Log("Relinking Reference scripts...");
GameManager.Instance.FindReferenceScripts();
}
}
Again, this error doesn't seem to trigger on the first few scene loads. It also doesn't seem to have any difference if the scene was one that had previously been loaded or not. I'm sorry if this is a lot to be asking for help with. My coding skills are still very much in training; most of what I do is based on tutorials or other such references I find online. Any help will be greatly appreciated.
Answer by JadeTheurgist · Dec 21, 2020 at 12:38 AM
I was able to find this answer with the help of a college professor. It wasn't even in one of the scripts I originally thought it was.
Tip for anyone trying to use Unity's new input system: have the input detection link to a defined function. DO NOT use a lambda expression to read the context right at input. It is what caused this bug. ie: Do this:
controls.Gamepad.ExtraAction2.performed += StrafeRight;
...and define the function later in the script.
Not this:
controls.Gamepad.ExtraAction2.performed += ctx => GameManager.Instance.dungeonMvr.StrafeRight();
Follow this Question
Related Questions
Pass a copy of a GameObject as variable to another script? 1 Answer
Do I NEED to handle the MissingReferenceException? 1 Answer
Missing Reference Exception @ GuiSkin...Gui Button 1 Answer
How to keep reference linked when replace prefab through editor scripts? 1 Answer
Unassigned Reference Exception ? 0 Answers