OnTriggerEnter NullReferenceException - Only in builds, works fine in editor

Hi, I have an issue that is driving me mad, and it happens only in builds, everything works fine when I play my game in the editor.

This code from my attack hitbox that tests to see if it hits the enemy collision capsule and then activates some scripts on it, works just fine. But when I create a windows build I am not able to hit the enemies and this is what I get in the log every time I take a swing at the enemies:

"Enemy_Collision is hit
NullReferenceException: Object reference not set to an instance of an object
at Hitbox.OnTriggerEnter (UnityEngine.Collider collision) [0x0004f] in :0 "

This is the part of my code that gives me the problem:

void OnTriggerEnter(Collider collision)
     {  
        if(collision.gameObject.CompareTag("Enemy_Collision"))
        {
            Debug.Log("Enemy_Collision is hit");
            EnemyHealthController _enemyHealthController = collision.gameObject.GetComponentInParent<EnemyHealthController>();

            if(_enemyHealthController)
            {
                Debug.Log("HealthController FOUND");

                _enemyHealthController.currentHealth = _enemyHealthController.currentHealth - damage;
                _enemyHealthController.UpdateHealth();
                Vector3 position = collision.transform.position + new Vector3(0f, 1f, 0f);
                Instantiate(enemyHitParticles, position, collision.transform.rotation);
                audioManager.Play("swordHitFlesh01");
                audioManager.Play("monsterPain02");

                //Knockback
                enemyAI = collision.transform.parent.gameObject.GetComponent<EnemyAI>();
                enemyAI.SetKnockbackValues(knockbackForce, transform.parent.position);
            } 
            else
            {
                Debug.Log("HealthController NOT found");
               
            }            
        }

If you have any suggestions what I can do to make this work in builds as well I would be very grateful :slight_smile:

Doesn’t matter. The answer doesn’t change. Step #1 is to find out what is null in the build.

NullReference is the single most common error while programming. Fixing it is always the same.

  • also known as: Unassigned Reference Exception
  • also known as: Missing Reference Exception
  • also known as: Object reference not set to an instance of an object

Don’t waste your life spinning around and round on this error. Instead, learn how to fix it fast… it’s EASY!!

Some notes on how to fix a NullReferenceException error in Unity3D:

http://plbm.com/?p=221

The basic 3 steps outlined above are:

  1. Identify what is null ← any other action taken before this step is WASTED TIME
  2. Identify why it is null
  3. Fix that.

Expect to see this error a LOT. It’s easily the most common thing to do when working. Learn how to fix it rapidly. It’s easy. See the above link for more tips.

You need to figure out HOW that variable is supposed to get its initial value. There are many ways in Unity. In order of likelihood, it might be ONE of the following:

  • drag it in using the inspector
  • code inside this script initializes it
  • some OTHER external code initializes it
  • ? something else?

This is the kind of mindset and thinking process you need to bring to this problem:

Step by step, break it down, find the problem.

Thank you so much for your in-depth reply!
I feel like I have done what you suggest, but have hit a point where I need help.

I have identified that this line of code is where the problem arises:

 EnemyHealthController _enemyHealthController = collision.gameObject.GetComponentInParent<EnemyHealthController>();

I guess I was hoping that someone could tell me why that code is wrong. And why I need to do it differently for it to work in the built game.

Any input will be dearly appreciated :slight_smile:

Based on the code posted above and the bracketing of Debug.Log() messages, it certainly appears that your conclusion about where the null is must be correct.

So move on!

Comment out 100% of the code that USES that _enemyHealthController later in the method, like make this thing do nothing apart from get the controller. Does it still crash?

If it doesn’t, now start putting back those lines you commented out.

EDIT: the unguarded stuff like enemyAI and to a lesser degree audioManager are also suspect separately… test those separately and see. I say lesser degree for audioManager because it’s external, whereas enemyAI is untested crazy parented Wheres Gamewaldo? code. :slight_smile:

ALSO, just generally here’s some more reading:

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.

Here’s the bare minimum of stuff you absolutely MUST keep track of if you insist on using these crazy Ninja methods:

  • what you’re looking for:
    → one particular thing?
    → many things?
  • where it might be located (what GameObject?)
  • where the Get/Find command will look:
    → on one GameObject? Which one? Do you have a reference to it?
    → on every GameObject?
    → on a subset of GameObjects?
  • what criteria must be met for something to be found (enabled, named, etc.)

If you are missing knowledge about even ONE of the things above, your call is likely to FAIL.

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

Botched attempts at using Get- and Find- are responsible for more crashes than useful code, IMNSHO.

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.

thanks again for more useful info, Kurt-Dekker!
I will dig deeper as you suggest.

In the meantime I would love to hear if you can point me in a direction of the “right” way of accessing a component on the enemy I hit. I don’t think the public field/drag into inspector way will work for dynamically hitting one of many enemies? Are there some best practices for this type of OnCollision situations that I should follow?

And, in case you have any useful tips on what to look out for in regards to running in editor vs running in builds, I would love to hear more :slight_smile:

Thanks

The key is to do as few GetComponent calls as possible. And when you do them, be diligent about what where when why how, etc., and handle error codes.

In the case above, have a root EnemyController (or even an EnemyAdaptor) that might have other components alongside it, such as the AI, and that EnemyController knows how to get at whatever AI it has, and handles not having it, either with a clear error, or other default behaviour.

“But wait a second Dekker, doesn’t that tie EnemyAI to EnemyController?”

I’m glad you asked!

Look at your code now: whatever thing this little collision code is in is already ASSUMING an EnemyController has an EnemyAI, so not only is it already tied, it’s not even tied ANYWHERE that EnemyController or EnemyAI could show, control, mediate, complain about, and anyone looking at these two classes could never know about!!

So yeah, there’s never one perfect way, but minimize who knows what, centralize the knowledge, and make that part bulletproof with tons and tons of error-checking.

Organizing code is hard. About the only other “best practice” is to be nimble and ready to completely throw out what you have already and redo it better. You do gain knowledge every day you work in a project, and a project is always changing. This is called refactoring. I’m not saying you should refactor the above, I’m simply pointing out that when you code with a mind that everything you write is disposable, when something misbehaves, study it, improve it, delete it, rewrite it, move forward.