Can someone explain why Unity only TEMPORARILY sets the reference on Start() instead of keeping it?

This whole thing makes no sense to me.

When I make the variable public and assign the reference script in the editor itself, the script reference stays and it doesn’t return null, as it should.

So, if I wanted to set the reference from the script itself, I would find and set the reference, for example, by doing:

referenceScript = GameObject.FindGameObjectWithTag("TagExample").GetComponent<ReferenceScript>();

This should actually SET the value right? Well it does, but KIND OF. That’s exactly where I don’t understand what is going on.

If I put the code on Start(), it does set the value, but THEN when I want to do something with the ReferenceScript, in a method for example, I get the old fashioned error:

“NullReferenceException: Object reference not set to an instance of an object.”

Why? Didn’t you just SET the value? Why you first SET it, and right after that immediately return null?

So because of this, I have to continuously set the value every time that specific method is called. This is the only way I can get it to work.

This also only happens for script references, it has no problem with, say for example, Rigidbody or WheelCollider, etc.

Why it does this? Is it some kind of thing to save memory, so it removes it instead of keeping it?

Please post your entire code. It is pointless to talk about code issues in an abstract way. There is no „it kind of works but doesn‘t“ when it comes to code. Either you have a bug, or you make incorrect assumptions. Without the code, none of us can tell.

I’m not doing a bug report here. It’s a known thing and everyone recommends you to set the value every time your method is called, it just how it behaves, I just want to learn why.

Nobody here knows how your program runs. That’s for you to find out through debugging.

Time to start debugging! Here is how you can begin your exciting new debugging adventures:

You must find a way to get the information you need in order to reason about what the problem is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the names of the GameObjects or Components involved?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as Debug.Log("Problem!",this);

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: https://discussions.unity.com/t/700551 or this answer for Android: https://discussions.unity.com/t/699654

If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

If your problem is with OnCollision-type functions, print the name of what is passed in!

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

https://discussions.unity.com/t/839300/3

“When in doubt, print it out!™” - Kurt Dekker (and many others)

Note: the print() function is an alias for Debug.Log() provided by the MonoBehaviour class.

Finally, for fixing the actual problem:

The answer is always the same… ALWAYS!

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Three steps to success:

  • Identify what is null ← any other action taken before this step is WASTED TIME
  • Identify why it is null
  • Fix that

No, everyone does not recommend that. What you just described is very much NOT how this normally behaves. I am making a game and have zero problems with setting references to scripts, and then using those references elsewhere.

Either, the referenced script is being deleted (along with the game object it is on), or you have multiple of the same script attached to objects, and only some of them are setting the reference, and some are not. We need to see the code or we can’t actually help determine what the cause is.

There’s no reason for the script/gameobject being deleted, as I said in my post that it DOES reference when I call it within the method.

There’s no script to provide, as it always happens no matter which script it’s in. But the code is simply:

referenceScript = GameObject.Find("GameObjectExample").GetComponent<ReferenceScript>();

I saw a post related to finding an object and getting a script component from it on Stack Overflow, they said that the script had to be referenced again WITHIN the method that reads/modifies the Reference Script, and not on Start().

The GameObject IS stored, but you have to get the script component again. For example;

void Start()
{
referenceObject = GameObject.Find("Object");
}

...
void ExampleMethod()
{
referenceScript = referenceObject.GetComponent<ReferenceScript>();
referenceScript.exampleValue = 1;
referenceScript.MethodName();
...
}

This is the only way it works, however if you do THIS:

void Start()
{
referenceScript = GameObject.Find("Object").GetComponent<ReferenceScript>();
}

...
void ExampleMethod()
{
referenceScript.exampleValue = 1;
referenceScript.MethodName();
...
}

Then it gives you an NullReferenceException error when you call the ExampleMethod().

Well, there’s your problem! Right in front of you!!

You are blatantly violating the first rule of GameObject.Find():

Remember the first rule of GameObject.Find():

Do not use GameObject.Find();

Even if you REALLY REALLY REALLY want to use GameObject.Find(), DO NOT USE GAMEOBJECT.FIND.

More information: https://starmanta.gitbooks.io/unitytipsredux/content/first-question.html

More information: https://discussions.unity.com/t/899843/12

In general, DO NOT use Find-like or GetComponent/AddComponent-like methods unless there truly is no other way, eg, dynamic runtime discovery of arbitrary objects. These mechanisms are for extremely-advanced use ONLY.
If something is built into your scene or prefab, make a script and drag the reference(s) in. That will let you experience the highest rate of The Unity Way™ success of accessing things in your game.

Keep in mind that using GetComponent() and its kin (in Children, in Parent, plural, etc) to try and tease out Components at runtime is definitely deep into super-duper-uber-crazy-Ninja advanced stuff.

This sort of coding is to be avoided at all costs unless you know exactly what you are doing.

If you run into an issue with any of these calls, start with the documentation to understand why.

There is a clear set of extremely-well-defined conditions required for each of these calls to work, as well as definitions of what will and will not be returned.

In the case of collections of Components, the order will NEVER be guaranteed, even if you happen to notice it is always in a particular order on your machine.

It is ALWAYS better to go The Unity Way™ and make dedicated public fields and drag in the references you want.

^ ^ ^ This is exactly what happens when you use GameObject.Find(). Things make no sense whatsoever. Your mind WANTS it to work, you desperately want it to have a place in your palette of tools… but it doesn’t. GameObject.Find() is NOT TO BE USED.

I wouldn’t be using it if I didn’t need it, I’m not dumb.

While I agree that it’s better to assign it within Unity’s serialized field, the reason I’m using it is because what I’m trying to reference is not always there.

Say I have multiple prefabs, and only one of them is being loaded, which is either randomly chosen or by player. Every single of them has the exact same script. If I drag (reference) the one on the Prefab A, and player chooses Prefab B instead, then it won’t simply work because it’s referencing to the ExampleScript on Prefab A, and not the one on B.

So, rather than manually assigning all of them to the list (which isn’t quite practical), you want to use GameObject.Find(), or in my case, GameObject.FindGameObjectWithTag(“TagName”), so when the scene and the selected Prefab is loaded, it finds and references that one instead.

Keep one additional thing in mind. You probably know this, but I will say it anyway. If you make ANY code changes and save them while the editor is running, the default behavior of Unity is to recompile, while allowing the editor to continue playing. When this happens, tons of references to objects on the Heap are lost, so values that should be set are suddenly null references. If you can tell that no code compilation is occurring in play mode before this issue occurs, then this obviously isn’t the cause of your problems. Still worth a mention, especially if someone finds this thread in the future because they are having mysterious null ref issues.

It just sounds like you’re trying to get at it when it’s not there.

This stuff isn’t hard, don’t make it hard on yourself. Seriously. Move up the value chain. Spend your effort where it benefits you: make your dream game, play your dream game.

Don’t be wrestling with all the filthy dirty pigs down in the nullreference slop farm. That’s the LAST place you wanna be.

Use one of the simple locator patterns that StarManta posts above.

Here’s the one I always use for transient services:

And finally there’s always just a simple “static locator” pattern you can use on MonoBehaviour-derived classes, just to give global access to them during their lifecycle.

WARNING: this does NOT control their uniqueness.

WARNING: this does NOT control their lifecycle.

public static MyClass Instance { get; private set; }

void OnEnable()
{
  Instance = this;
}
void OnDisable()
{
  Instance = null;     // keep everybody honest when we're not around
}

Anyone can get at it via MyClass.Instance., but only while it exists.

If you want this service to just appear when needed:

Simple Singleton (UnitySingleton):

Some super-simple Singleton examples to take and modify:

Simple Unity3D Singleton (no predefined data):

Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance

what value do you get if you do a debug.log on that referencescript - it could easily be null if the object didnt exist at the time of start running.

I once thought the same thing, but it does print the object name.
9216222--1286172--upload_2023-8-12_21-29-38.png

and theres no way that got destroyed since? or theres another copy of the script? this one, not the referenced script