GameObject.Find does not work in Android build after reloading Scene - c#

I have two Scenes in Unity. First one is for importing data from a binary file and after file is imported i create a gameobject with the coordinates i read from the binary file. I use DontDestroyOnLoad for this game object.
Then i load my second scene using AsyncOperation and find my object using GameObject.Find. This works fine and i can find the object and do my operations. However, in my second scene i have a reset button with which i reload the same scene using AsyncOperation. When scene is reloaded GameObject.Find can not find my object. By the way this only happens in Android build. In Editor it finds the object there is no problem.
This is how i reload the scene my ResetScene function gets called when button is pressed.
void ResetScene()
{
StartCoroutine(LoadAsyncScene());
}
IEnumerator LoadAsyncScene()
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("ARSession");
while (!asyncLoad.isDone)
{
yield return null;
}
}
Does anyone have any idea why this issue occurs or does anyone have a better idea for finding object? Since i create the object in runtime i feel like i have no option other than GameObject.Find. Any help would be appreciated. Thanks!
Note: I tried finding the object in Start and OnLevelWasLoaded. Both of them did not work.
I logged every game object in hierarchy using this:
foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
{
Debug.Log(obj.name);
}
In initial load my the game object i created is logged but after i reloaded the scene my object is not loaded.
I actually found the source of the problem. I was changing the parent
of my object from null to another object and apparently this causes
the issue. However, i do not know how to fix this because i must
change the parent i can't change that logic.

I actually found the solution. I did not realize the problem is caused because of changing the parent when i asked the question.
DontDestroyOnLoad only work for root GameObjects
Therefore, when i added a parent to my object my object is destroyed. Making the parent null alone was not enough. DontDestroyOnLoad has to be applied again. The solution i found was like this:
void ResetScene()
{
test.transform.parent = null;
DontDestroyOnLoad(test);
StartCoroutine(LoadScene());
}

Related

Loading scene in Unity makes the references in that scene null

I am making my first game in Unity and I'm trying to load the first level of it when the cutscene at the start ends. I don't know if it's possible to make the script do something after a video clip ends, so I wrote my code like this:
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class CutsceneEnd : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
StartCoroutine("wait");
}
IEnumerator wait()
{
yield return new WaitForSeconds(36);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
But the problem is not with my method of waiting for the end of the video, it's with the scene it loads. I can't move my character because all the references in the scripts are null. I have no idea what I did wrong.
Unity references should be stored in the scene file. Are you using any source control like git? If someone else did not push the changes to the .unityscene file or the .meta files for the associated scripts/prefabs, it might break the references.
I think we need some more information here.
If you referring to references (public variables) to Assets/GameObjects in the loaded scene, then you may have simply never placed the references in the first place. Unity's public variables should be saved within the Scene file and should always load with the Scene.
Double check to see if the references are actually null. Are you using an animation when you load into the Scene? This can keep you from being able to manual move anything. For example, if you animate the character when loading the scene, it could get stuck in the animation clip and you won't be able to move it.
Lastly, if you are referring to references created within the code to other scripts, objects, or variables, then these may break between scenes if you don't utilize 'DontDestroyOnLoad'.
Just spit-balling here, I need more information to correctly find the solution.

Neither null nor type check detecting destroyed object/component?

I have an issue for which I've found a workaround, but can't understand why Unity isn't working the way I expect, or what I'm doing wrong. Basically, I am referencing a renderer component of a destroyed object in a script (long after it's been destroyed), and neither null checks nor type checks let me know it's destroyed.
I have a script that's modifying the shaders on some objects temporarily so I can apply effects on to them; when the effects are done it puts the materials/shaders back the way they were.
It happened that I was swapping out a character's weapon in the same frame I began one of these effects, so the script wound up with a reference to the renderer of a destroyed object (the old weapon). Many frames later when the effect was to finish, it naturally err'd out.
I tried a type check first to see if the reference was still to a renderer -- no luck. Unity's doc says a null check should work, but it still doesn't.
if (pair.Key != null && pair.Key is Renderer renderer) { renderer.materials = pair.Value; }
I get:
MissingReferenceException: The object of type 'SkinnedMeshRenderer' 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.
activeInHierarchy likewise does not work.
Adding a DestroyImmediate to the code where I destroy the object works fine; the object isn't there by the time the effect starts, so the reference is never made. However, that only solves this one problem, and not other such cases.
Can anyone tell me how to check properly for references to destroyed objects or components, or if I'm doing something wrong in my checking? Should I be referencing the gameObject instead of the renderer component or something like that?
EDIT:
Since a commenter asked for it, here's a gist of the full code for the effect. The destruction is happening outside this, as it's totally unrelated.
https://gist.github.com/jackphelps/f507d949a84c53457f570c5009bcb6d4
SOLVED -- SORT OF?
I changed the dictionary to store the renderer's game object instead of the renderer, and as expected a simple null check worked for detecting a destroyed object. I'd love to know why it doesn't work on the renderer, and if there's a proper way to check!
The best way I could find to solve this was to store a reference to the renderer's gameObject rather than to the renderer component itself. In this case, a simple null check at the end of the script works fine, as expected.
I'm not accepting this answer because it still doesn't tell me how to check for a component's presence when the game object was removed ¯(°_o)/¯

Unity: Camera.main is failing after I switch scenes

I am having a weird issue with some of my code, and I could really use some help.
I have a script attached to a gameobject that is unique to a particular scene, so anything within Start() will only run when that scene is loaded. In this script, I am accessing Camera.main, since I use settings attached to the camera gameobject (it may sound inefficient, but it is necessary for the style of game we are creating). Anyway, if I start from that scene directly in Unity, it works just fine, but if I start from my intro scene and then load into the aforementioned scene, I get this error:
MissingReferenceException: The object of type 'Camera' 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.
The weird thing is, I can Debug.Log(Camera.main) and it gives me the name of the camera. So Camera.main is not null, and it is not destroyed like it says in the error message. Here is my full script:
private void Start()
{
Debug.LogError(Camera.main);
gameManager = FindObjectOfType<GameManagerScript>();
if (Camera.main == null)
{
Debug.LogError("Camera.main is null");
}
else
{
gameManager.LoadMusic(Camera.main);
gameManager.LoadAmbient(Camera.main);
gameManager.FadeStereoPan(Camera.main.gameObject.GetComponent<SwipeActivator>().stereoPanInNode);
}
}
The three functions above are custom functions I wrote, but I don't know why they would be causing the issue, since they work if I start up the scene directly.
I wasn't having this issue for months, and then all of a sudden, I am getting this error, even though I didn't change any of the code. Any help would be greatly appreciated.
I believe your MainCamera is being destroyed between scenes. Set it up as "DontDestroyOnLoad()"
See this Unity question:
https://answers.unity.com/questions/430141/need-the-same-main-camera-for-multiple-scenes.html
Ah, I fixed it. I dove into my custom functions and found that I was accessing a camera variable that is set at the beginning of the game, and then on each camera transition, but it was failing since I was loading a scene and no transitions that scene had yet to be completed. I just had to reassign that variable in the script above so it was not pointing to the destroyed object in the previous scene. Thank you JiveTurkey for pointing me in the right direction!

Why isn't my resource loaded when calling Resources.FindObjectsOfTypeAll()

I have a method in my game that dynamically finds and instantiates prefabs into my scene like this
public void CreateAgent(string agentName)
{
var prefabs = Resources.FindObjectsOfTypeAll<Agent>();
var selectedPrefab = prefabs.Where(p => p.name == agentName).FirstOrDefault();
Instantiate(selectedPrefab.gameObject);
}
This works sometimes, but it seems like sometimes the resource for my prefab hasn't been loaded, so Resources.FindObjectsOfTypeAll() doesn't return the resource that I want to load. I can resolve that by calling Resources.LoadAll<Agent>("MyPrefabDirectory") first, but I'm not sure if doing that during gameplay will cause problems or slow the game down. It also seems like Unity is unloading previously used resources, because I can load prefab A into my scene, then load a new scene, and when I try to load prefab A in the new scene, that results in prefab A not being found by Resources.FindObjectsOfTypeAll()
So my questions are
Why do I have to call Resources.LoadAll() before Resources.FindObjectsOfType() will find my prefab?
Why is Unity unloading a previously loaded resource when I change scenes?
Is calling Resources.LoadAll<MyResourceType>() during gameplay bad?
From the documentation
Resources.FindObjectsOfType():
This function can return any type of Unity object that is loaded.
Why is Unity unloading previously loaded resources? To save memory. If its not being used, its going to get garbage collected.
Considering that you're only going to be using one of the returned objects, you should probably refactor to just call Load on the single object you actually need.

How can I fix MissingReferenceException that is telling me game object is destroyed when I didn't destroy it?

I have code that looks like this.
public static Dictionary<int, Action> functionsMap;
void Function()
{
if (!isDictionaryInitialized)
{
functionsMap = new Dictionary<int, Action>();
functionsMap.Add(1, () => StartCoroutine(Function1()));
functionsMap.Add(1, () => StartCoroutine(Function2()));
}
}
void CheckForFunction()
{
var r = currentFunctionNumber;
if (functionsMap.TryGetValue(r, out currentAction)) { currentAction(); }
}
The code works fine when I start my program. However if I go to another scene and then return to it, I get this error.
"MissingReferenceException: The object of type 'ScriptName' 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."
The problem is I have never destroyed the object. Initially I didn't have bool isDictionaryInitialized and I defined the new Dictionary outside of the Function because I thought the error was related to my program trying to access a Dictionary that was deleted after the scene was closed. I get the same problem with or without the bool, and regardless of where I define the Dictionary.
What is causing this, and what is the reason so I can avoid making the same mistake?
Edit: This question was marked as duplicate, but the link I don't believe applies to my situation, or if it does I don't understand how. It says static objects are not reloaded on a scene change, and the Dictionary is defined as a static object. I also tried changing it to non-static and the result is the same.
I have dozens of gameobjects in my code and don't have this issue with any other object, so I assume the problem is related to how the dictionary object is defined. Is there a way to keep the Dictionary object from being destroyed on scene change? I don't have it as a game object in the scene, it's just defined in the code itself as a public static Dictionary. Could someone tell me what I need to do differently please and thank you?
The problem might be caused by changing scenes because simply loading another scene would destroy all gameobject in the current scene.
According to Object.DontDestroyOnLoad.
The load of a new Scene destroys all current Scene objects.
To solve this, you can either use DontDestroyOnLoad function to mark the object you want to be kept before loading another scene, or using different way to load like LoadSceneMode.Additive without destroying the current scene.
First you are adding two Actions to your Dictionary but both with the same key.
functionsMap.Add(1, () => StartCoroutine(Function1()));
functionsMap.Add(1, () => StartCoroutine(Function2()));
wouldn't this overwrite the first entry?
Than your general problem is:
While functionsMap is static the two actions / one action you added are non-static (StartCoroutine always requires an instance of MonoBehaviour to run on) and therefore only available for the according component! (You talked about an Update method so this has to be a MonoBehaviour attached to a GameObject in your first scene.)
Now if you change the Scene, the GameObject holding that component is probably destroyed if you are not using DontDestroyOnLoad
The result is that your static Dictionary stays intact and filled meaning the entry with key = 1 still exists but the Value namely the added non-static Action is no longer available.
To avoid that you should add
DontDestroyOnLoad(this.gameObject);
either in Awake or Start to prevent the GameObject holding the component and thereby holding the Action that belongs to the reference(s) in the entry in your Dictionary.

Categories