null references caused by script/function execution order?

HI all unity Gurus,
I’m trying to get my head around how scripts execute, and why I am getting random null reference errors trying to access objects and functions across several scripts. I’m about two days into C# and unity scripting (but I have a lot of experience game programming in many other languages and systems, has been easy to pick up quickly, except for:

It seems that Update() functions interrupts the normal flow of a program - is that true?

For example, in a Tower Defense game, I have several guns placed and several moving targets. Each target might be in range of several guns, but a gun locks on to one target at a time and fires at it until it moves out of range or is destroyed. Once that happens it moves on to acquire a new target.

In order to implement this, each instance of a gun and each of a target has a script, and in the script each maintains a hashtable of target instance ids/ target gameObject pairs; and gun instance ids/ gun gameObject pairs, respectively. A given gun’s list contains which targets are in range, and a target’s list contains all the guns that have it in range.

When a target moves in or out of range or is destroyed the hashtable of a single gun (or multiple guns’) script needs to be maintained, so that the target reference can be removed and, if necessary, a new target acquired by iterating through the list. The target’s list will be used to notify the gun that the target is no longer available when it is destroyed.

At a basic level this strategy works. The problem is, sometimes, rather randomly, the target is destroyed before it can be removed from the list, so the hashtable update generates an out of sync error. And at other times, the taget has been destroyed before the gun’s update function can know about it.

I’ve been tracing with print statements and the debugger, and the order of execution of functions and update() just does not make sense to me.

For example, I have function 1 call function 2. I should see them execute in that order, and most of the time they do, but sometimes an Update can come between them. I can hardly believe what I am seeing… am I dreaming all this, or what? Everything seems so completely random.

Is there any way of predicting the order in which functions are called, or some other strategy to handle the kinds of errors I am talking about? Would it be easier if I did everything from 1 script, rather than having scripts attached to each object?

Thanks for your ideas!

I’m not sure about the supposed randomness you’re reporting; I don’t think that’s a thing.

However, unless you explicitly set the Order Of Execution for your scripts in the project settings, Unity will make the decision for you. This is usually fine, especially if you adhere to certain design philosophies Unity encourages. Very occasionally this can create a snowballing problem where you must set the OOE for multiple inter-dependent scripts; that’s usually a red flag your approach needs refactoring. (events, manual invocation of initialization logic, etc)

That said, this specific issue as described sounds unrelated to execution order of scripts - more likely it’s execution order of functions; maybe a careless error or edge case. Your report of Update interjecting between function calls is very unusual. Not sure what you’re witnessing there, but Unity’s execution flow is most definitely structured to avoid any such tomfoolery.

There are caveats and special cases to consider though; for instance, objects are not destroyed until the end of the frame in which Destroy is invoked. Little fiddly things like this may be overlooked and crop up as mysterious exceptions.

I don’t discern anything wrong with your described methodology for tracking objects, except that I wonder why hashtables are your preference here. I doubt that is related to your issue. Once you get familiar with its quirks and adopt its most critical preferred practices, Unity is quite strong & reliable.

Check out this lifecycle to understand what where when and why.

Also I think that it would be useful for you to read about triggers and colliders.

Also check for null where it is critical (e.g. != or == null).

If you want a guidance on your particular code then we would need it :smiley: