Object reference not set to an instance of an object for combat script

im working on a combat script and when it goes to deal damage to the enemy it says “Object reference not set to an instance of an object” on line 31 of “PlayerCombat”
I have a component in the enemy object named “Enemy” which is a script.

PlayerCombat

using UnityEngine;

public class PlayerCombat : MonoBehaviour
{
    private float timeBtwAttack;
    public float startTimeBtwAttack;

    public Transform attackPos;
    public LayerMask whatIsEnemies;
    public Animator playerAnim;
	public Vector3 attackRange = new Vector3(0.0f, 0.0f, 0.0f);
	public int damage;

	// Start is called once before the first execution of Update after the MonoBehaviour is created
	void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(timeBtwAttack <= 0)
        {
            if (Input.GetKey(KeyCode.Z))
            {
                playerAnim.SetTrigger("Attack");
				Collider2D[] enemiesToDamage = Physics2D.OverlapBoxAll(attackPos.position, attackRange, whatIsEnemies);
                for (int i = 0; i < enemiesToDamage.Length; i++)
                {
                    enemiesToDamage[i].GetComponent<Enemy>().TakeDamage(damage);
				}
            }

            timeBtwAttack = startTimeBtwAttack;
		} else
        {
            timeBtwAttack -= Time.deltaTime;
		}
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube(attackPos.position, attackRange);
	}
}

“Enemy” script

using UnityEngine;

public class Enemy : MonoBehaviour
{
    public float health;

    private Animator anim;
    public GameObject hitEffect;

	// Start is called once before the first execution of Update after the MonoBehaviour is created
	void Start()
    {
        anim = GetComponent<Animator>();
	}

    // Update is called once per frame
    void Update()
    {
        if (health <= 0)
        {
            Destroy(gameObject);
		}
	}

    public void TakeDamage(int damage)
    {
        Instantiate(hitEffect, transform.position, Quaternion.identity);
        health -= damage;
        Debug.Log("Enemy health: " + health);
	}
}

Does your enemy gameObject have a child object with a collider?. I suspect there’s a gameObject with a collider on your whatIsEnemies layer that doesn’t have an Enemy script. Line 31 assumes that every collider is on a gameObject with an Enemy script.

BTW - it would be cleaner to move the health check and Destroy into your TakeDamage method.

the only object on the whatIsEnemies layer is the enemy object, the enemy object has an Enemy script in it yet it still thinks it doesn’t. idk what’s causing it, i checked every post i could on it and nothing helped.

im trying to follow this video btw https://www.youtube.com/watch?v=1QfxdUpVh5I&t=3s

The answer is always the same… ALWAYS!

How to fix a NullReferenceException error

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

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

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

Debugging advice:

Line 31 is in this section:

Collider2D[] enemiesToDamage = Physics2D.OverlapBoxAll(attackPos.position, attackRange, whatIsEnemies);
      for (int i = 0; i < enemiesToDamage.Length; i++)
      {
          enemiesToDamage[i].GetComponent<Enemy>().TakeDamage(damage);
	    }

Specifically this line:

enemiesToDamage[i].GetComponent<Enemy>().TakeDamage(damage);

Physics2D.OverlapBoxAll will return you an array of Collider2D.
Link: Unity - Scripting API: Physics2D.OverlapBoxAll

enemiesToDamage[i] will be a Collider2D. Calling GetComponent<Enemy>() on that tries to get and return an Enemy component from the GameObject that the Collider2D is on. If the GetComponent call fails (no Enemy component on that GameObject), it returns null, then you get a null reference exception, which is what you are getting:

“Object reference not set to an instance of an object."

This means “We tried to look at the reference you pointed us to and use it, but there was nothing there (no object), aka. null. You tried to operate on something that was null, and that doesn’t work. Here is an error.”

You would also get a null reference exception if enemiesToDamage[i] was null (which is probably not the case in this instance).

One way to debug this is to see what your Physics2D.OverlapBoxAll is actually returning/seeing. Comment out your GetComponent call in the for loop, and replace it with a Debug.Log call that logs the name of the GameObject being looked at. That will look like this:

Collider2D[] enemiesToDamage = Physics2D.OverlapBoxAll(attackPos.position, attackRange, whatIsEnemies);
      for (int i = 0; i < enemiesToDamage.Length; i++)
      {
          // enemiesToDamage[i].GetComponent<Enemy>().TakeDamage(damage);
          string colliderGameObjectName = enemiesToDamage[i].gameObject.name;
          Debug.Log(colliderGameObjectName);
	    }

Then it will log to your Console window the names of the game objects you actually hit. So you can see the first step of what is happening. The way the code is written right now, if any Collider2D that you hit doesn’t have an Enemy script on it, the code will try to operate on that Enemy script (which is actually null) and throw a null reference exception.

There are multiple ways you could change your code to deal with this, but for now, just figure out what your OverlapBoxAll is actually hitting. Debugging physics casts like this is a very valuable skill to learn. Visual debug gizmos is a good thing to learn to do, and text logging (which I suggest here) is good as well.

Good luck.

I already did, the thing thats null is that it can’t find the Enemy script in the enemy object.

That’s the part I’m stuck on, I have no idea why its doing this because I have a Enemy script in the enemy object but the script can’t find it for some reason (either that or the hitbox is checking everything it touches including the player instead of just the things with the “Enemy” tag which i doubt as the code only checks for things with the tag that the hitbox is touching).

I can’t as i don’t know why its broken.

CCevers post is good advice. In ray cast/overlay situations like this you need to work out what you’re actually hitting so you can start to reason why its not what you expect.

Break that big long hairy line apart, the one that CCEvers notes above.

Tutorial makers that write code like this do everybody a disservice because now something as simple as forgetting one other unrelated step causes that line to barf.

If you have more than one or two dots (.) in a single statement, you’re just being mean to yourself.

Putting lots of code on one line DOES NOT make it any faster. That’s not how compiled code works.

The longer your lines of code are, the harder they will be for you to understand them.

How to break down hairy lines of code:

Break it up, practice social distancing in your code, one thing per line please.

“Programming is hard enough without making it harder for ourselves.” - angrypenguin on Unity3D forums

“Combining a bunch of stuff into one line always feels satisfying, but it’s always a PITA to debug.” - StarManta on the Unity3D forums

As others have already pointed out, one of the Unity objects in the enemiesToDamage array does not have the Enemy script attached. The fix is straightforward: update the code to check whether the Enemy component exists before calling TakeDamage.

There are two common ways to do this.

  1. Using a null check:
for (int i = 0; i < enemiesToDamage.Length; i++)
      {
           var tempEnemy =  enemiesToDamage[i].GetComponent<Enemy>();
           if( tempEnemy != null)
           {
                  tempEnemy.TakeDamage(damage);
           }
      }
  1. Using TryGetComponent:
for (int i = 0; i < enemiesToDamage.Length; i++)
      {
          if(enemiesToDamage[i].TryGetComponent<Enemy>(out Enemy tempEnemy)
          {
                tempEnemy.TakeDamage(damage);
          }
      }

There are other approaches as well (for example, tagging only objects that represent enemies), but the core idea is the same:
You must identify which objects returned by OverlapBoxAll actually have the Enemy script and only call TakeDamage on those.