Search Unity

Error Message NullReferenceException: Object reference not set to an instance of an object

Discussion in '2D' started by ky0to_, Feb 21, 2021.

  1. ky0to_

    ky0to_

    Joined:
    Apr 12, 2020
    Posts:
    4
    The full error message is:
    NullReferenceException: Object reference not set to an instance of an object
    PlayerAttack.Update () (at Assets/Scripts/PlayerAttack.cs:26).
    I am currently working on a 2d game similar to Binding of Isaac that uses procedural generation. This particular script allows the player to damage enemies by using a physics2D overlap circle. The error actually triggers every time the player hits an enemy. I've spent hours trying to figure out what is wrong with my code and, but can't quite crack it! Thanks very much for your help, I'm sure there's a simple fix but I'm a beginner in Unity.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerAttack : MonoBehaviour
    6. {
    7.     private float timeBtwnAttack; //the amount of time between each attack (so the player can't spam it)
    8.     public float startTimeBtwnAttack;
    9.  
    10.     public Transform attackPos;
    11.     public LayerMask whatIsEnemies;//ensures player only attacks enemies
    12.     public float attackRange;
    13.     public int damage;
    14.     EnemyFollow TakeDamage;
    15.  
    16.  
    17.     void Update()
    18.     {
    19.         if(timeBtwnAttack <= 0) //if true, allows player to attack
    20.         {
    21.             if (Input.GetMouseButton(0)) //if player uses mouse left click (attack button in my game)
    22.             {
    23.                 Collider2D[] enemiesToDamage = Physics2D.OverlapCircleAll(attackPos.position, attackRange, whatIsEnemies); //casts circle in a certain position and radius, and enemies inside it take damage.
    24.                 for (int i = 0; i < enemiesToDamage.Length; i++)
    25.                 {
    26.                    enemiesToDamage[i].GetComponent<EnemyFollow>().TakeDamage(damage); //reduces enemy health
    27.                 }
    28.  
    29.                 timeBtwnAttack = startTimeBtwnAttack; //resets attack timer
    30.             }
    31.  
    32.          
    33.         }
    34.         else
    35.         {
    36.             timeBtwnAttack -= Time.deltaTime; //gradually decreases value of timer
    37.         }
    38.  
    39.  
    40.  
    41.     }
    42.  
    43.     private void OnDrawGizmosSelected() //helps visualise range and shape of player's attack in scene view
    44.     {
    45.         Gizmos.color = Color.red;
    46.         Gizmos.DrawWireSphere(attackPos.position, attackRange); //draws sphere mirroring attack position and radius
    47.     }
    48.  
    49. }
     
  2. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,510
    The error says line #26 so let's look at that line:
    enemiesToDamage[i].GetComponent<EnemyFollow>().TakeDamage(damage);


    Something here is producing a null-reference exception, meaning that you're trying to use an object that is in fact null. Sometimes it's a good idea to code in such a way that there's not so much happening on a single line so that when you get an error like this it's obvious. But here, I think we can figure out what could be null.

    enemiesToDamage[i]
    Could this be null? Probably not. Physics2D.OverlapCircleAll doesn't return nulls in its array: https://docs.unity3d.com/ScriptReference/Physics2D.OverlapCircleAll.html When something isn't found, the array is zero-lengthed, not filled with nulls.

    enemiesToDamage[i].GetComponent<EnemyFollow>()
    Could this be null? Yup - this is probably it. GetComponent returns null when the component (EnemyFollow) is not found on that object.

    So you're trying to invoke .TakeDamage on an EnemyFollow object that is null. That's what throws the exception.

    To fix, you need to make sure that the component EnemyFollow exists on that gameobject. Alternatively, if you have some enemies that will have that component and some that do not, then you could use
    Code (CSharp):
    1. if(enemiesToDamage[i].TryGetComponent(out EnemyFollow ef))
    2.    ef.TakeDamage(damage)
    If all enemies have that component, then TryGetComponent would be unnecessary.
     
    Last edited: Feb 21, 2021
    ky0to_ likes this.
  3. ky0to_

    ky0to_

    Joined:
    Apr 12, 2020
    Posts:
    4
    Thanks for the reply! The problem is, my enemy takes damage but the error message comes up anyway, and the player's attack speed is always the same (triggering every time the button is pressed) no matter the value I set it to the inspector. I checked, and all of the enemy gameobjects definitely have the enemyfollow script, but I can attach this script below just in case. Thanks again!
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class EnemyFollow : MonoBehaviour
    6. {
    7.     //public Transform player;
    8.     public float moveSpeed = 5f;
    9.     private Rigidbody2D rb;
    10.     private Vector2 movement;
    11.     //Animator anim;
    12.     public bool facingRight = true;
    13.     private Transform target;
    14.     public int health;
    15.    
    16.    
    17.    
    18.  
    19.  
    20.     void Start()
    21.     {
    22.        // anim = GetComponent<Animator>();
    23.         rb = this.GetComponent<Rigidbody2D>();
    24.         target = GameObject.FindWithTag("Player").transform;
    25.  
    26.     }
    27.  
    28.    
    29.     void Update()
    30.     {
    31.         Vector3 direction = target.position - transform.position; //direction of player object
    32.         direction.Normalize();
    33.         movement = direction;
    34.        
    35.     }
    36.  
    37.     private void FixedUpdate()
    38.     {
    39.         float horizontal = Input.GetAxis("Horizontal");
    40.         if (horizontal > 0 && !facingRight)        //flips player if they are moving right and facing left
    41.             Flip();
    42.         else if (horizontal < 0 && facingRight) //flips player if they are moving left and facing right
    43.             Flip();
    44.  
    45.         moveCharacter(movement);
    46.     }
    47.  
    48.     void moveCharacter(Vector2 direction)
    49.     {
    50.         rb.MovePosition((Vector2)transform.position + (direction * moveSpeed * Time.deltaTime)); //takes current position and moves towards player object
    51.     }
    52.  
    53.     void Flip()
    54.     {
    55.         facingRight = !facingRight; //switches the bool depending on the direction the player is facing
    56.         Vector3 theScale = transform.localScale;
    57.         theScale.x *= -1;
    58.         transform.localScale = theScale;
    59.     }
    60.  
    61.     public void TakeDamage(int damage)
    62.     {
    63.         health -= damage; //the damage is subtracted from the health
    64.         Debug.Log("damage taken!"); //to check the enemy is actually taking damage
    65.     }
    66.  
    67. }
    68.  
     
  4. ky0to_

    ky0to_

    Joined:
    Apr 12, 2020
    Posts:
    4
    I have solved the problem! I just had to mess around with the layers in my inspector as a lot of my components were in the wrong layer (so I just moved all my enemies to the water layer)! Thanks for your help, I really appreciate it!
     
  5. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,510
    Ah so you'll want to go through with the Visual Studio debugger and actually check out what those values are returning. For this, it may help to break up line 26 into several smaller statements so it's really easier to mouse over each of them to spot the null.

    If the debugger is new to you, it's super useful. Here are some tutorials: https://www.youtube.com/results?search_query=visual+studio+debugger+C#

    edit: looks like you got it
     
    ky0to_ likes this.