Forum begins after the advertisement:


[Part 3] NullReferenceException error on DestroyAfterAnimation

Home Forums Video Game Tutorial Series Creating a Metroidvania in Unity [Part 3] NullReferenceException error on DestroyAfterAnimation

Viewing 2 posts - 1 through 2 (of 2 total)
  • Author
    Posts
  • #19053
    MOHD YASAR
    Level 1
    Participant
    Helpful?
    Up
    0
    ::

    After adding DestroyAfterAnimation script

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class DestroyAfterAnimation : MonoBehaviour
    {
        // Start is called once before the first execution of Update after the MonoBehaviour is created
        void Start()
        {
            Destroy(gameObject, GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).length);
        }
    
    }

    it is showing a nullreferenceexception:object reference not set to an instance of an object i didn’t make the dust animation i directly make the slash animation. slash animation is working but after adding destroyafteranimation script it is showing nullreferenceexception. if anyone faces the same error please help me

    and this is my player controller script

    
    using System.Collections;
    using System.Collections.Generic;
    public class playercontroller : MonoBehaviour
    {
        [Header("Horizontal Movement Settings")]
        [SerializeField] private float walkspeed = 1;
        [Space(5)]
    
    
        [Header("Vertical Movement Settings")]
        [SerializeField] private float jumpForce = 45;
        private int jumpBufferCounter = 0;
        [SerializeField] private int jumpBufferFrames;
        private float coyoteTimeCounter = 0;
        [SerializeField] private float coyoteTime;
        private int airJumpCounter = 0;
        [SerializeField] private int maxAirJumps;
        [Space(5)]
    
    
        [Header("Ground Check Settings")]
        [SerializeField] private Transform groundCheckPoint;
        [SerializeField] private float groundCheckY = 0.2f;
        [SerializeField] private float groundCheckX = 0.5f;
        [SerializeField] private LayerMask WhatIsGround;
        [Space(5)]
    
    
        [Header("Dash Settings")]
        [SerializeField] private float dashSpeed;
        [SerializeField] private float dashTime;
        [SerializeField] private float dashCooldown;
        [Space(5)]
    
        [Header("Attacking")]
        bool attack = false;
        float timeBetweenAttack, timeSinceAttack;
        [SerializeField] Transform SideAttackTransform, UpAttackTransform, DownAttackTransform;
        [SerializeField] Vector2 SideAttackArea, UpAttackArea, DownAttackArea;
        [SerializeField] LayerMask attackableLayer;
        [SerializeField] float damage;
        [SerializeField] GameObject slashEffect;
    
    
    
        private Rigidbody2D rb;
        PlayerStateList pState;
        private float xAxis, yAxis;
        private float gravity;
        Animator anim;
        private bool canDash;
        private bool dashed;
    
    
    
        public static playercontroller Instance;
    
        private void Awake()
        { 
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
        }
    
    
        // Start is called once before the first execution of Update after the MonoBehaviour is created
        void Start()
        {
            pState = GetComponent<PlayerStateList>();
            rb = GetComponent<Rigidbody2D>();
            anim = GetComponent<Animator>();
            gravity = rb.gravityScale;
            canDash = true;
        }
        private void OnDrawGizmos()
        {
            Gizmos.color = Color.red;
            Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea);
            Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea);
            Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea);
        }
    
        // Update is called once per frame
        void Update()
        {
            Getinputs();
            UpdateJumpVariables();
            if (pState.dashing) return;
            Flip();
            Move();
            Jump();
            StartDash();
            Attack();
        }
    
        void Getinputs()
        {
            xAxis = Input.GetAxisRaw("Horizontal");
            yAxis = Input.GetAxisRaw("Vertical");
            attack = Input.GetMouseButtonDown(0);
        }
    
        void Flip()
        {
            if(xAxis < 0)
            {
                transform.localScale = new Vector2(-1, transform.localScale.y);
            }
            else if(xAxis > 0)
            {
                transform.localScale = new Vector2(1, transform.localScale.y);
            }
        }
        private void Move()
        {
            rb.linearVelocity = new Vector2(walkspeed * xAxis, rb.linearVelocity.y);
        }
    
        void StartDash()
        {
            if (Input.GetButtonDown("Dash") && canDash && !dashed)
            {
                StartCoroutine(Dash());
                dashed = true;
            }
    
            if (Grounded())
            {
                dashed = false;
            }
        }
    
        IEnumerator Dash()
        {
            canDash = false;
            pState.dashing = true;
            anim.SetTrigger("Dashing");
            rb.gravityScale = 0;
            rb.linearVelocity = new Vector2(transform.localScale.x * dashSpeed, 0);
            yield return new WaitForSeconds(dashTime);
            rb.gravityScale = gravity;
            pState.dashing = false;
            yield return new WaitForSeconds(dashCooldown);
            canDash = true;
        }
        void Attack()
        {
            timeSinceAttack += Time.deltaTime;
            if (attack && timeSinceAttack >= timeBetweenAttack)
            {
                timeSinceAttack = 0;
                anim.SetTrigger("Attacking");
    
                if (yAxis == 0 || yAxis < 0 && Grounded())
                {
                    Hit(SideAttackTransform, SideAttackArea);
                    Instantiate(slashEffect, SideAttackTransform);
                }
                else if (yAxis > 0)
                {
                    Hit(UpAttackTransform, UpAttackArea);
                    SlashEffectAtAngle(slashEffect, 90, UpAttackTransform);
                }
                else if(yAxis < 0 && !Grounded())
                {
                    Hit(DownAttackTransform, DownAttackArea);
                    SlashEffectAtAngle(slashEffect, -90, DownAttackTransform);
                }
            }
        }
        private void Hit(Transform _attackTransform, Vector2 _attackArea)
        {
            Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer);
    
            if(objectsToHit.Length > 0)
            {
                Debug.Log("Hit");
            }
            for(int i = 0; i < objectsToHit.Length; i++)
            {
                if(objectsToHit[i].GetComponent<Enemy>() != null)
                {
                    objectsToHit[i].GetComponent<Enemy>().EnemyHit(damage);
                }
            }
        }
        void SlashEffectAtAngle(GameObject _slashEffect, int _effectAngle, Transform _attackTransform)
        {
            _slashEffect = Instantiate(_slashEffect, _attackTransform);
            _slashEffect.transform.eulerAngles = new Vector3(0, 0, _effectAngle);
            _slashEffect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y);
        }
        public bool Grounded()
        {
            if (Physics2D.Raycast(groundCheckPoint.position, Vector2.down, groundCheckY, WhatIsGround)
               || Physics2D.Raycast(groundCheckPoint.position + new Vector3(groundCheckX, 0, 0), Vector2.down, groundCheckY, WhatIsGround)
               || Physics2D.Raycast(groundCheckPoint.position + new Vector3(-groundCheckX, 0, 0), Vector2.down, groundCheckY, WhatIsGround))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    
        void Jump()
        {
            if (Input.GetButtonUp("Jump") && rb.linearVelocity.y > 0)
            {
                rb.linearVelocity = new Vector2(rb.linearVelocity.x, 0);
    
                pState.jumping = false;
            }
    
            if (!pState.jumping)
            {
                if (jumpBufferCounter > 0 && coyoteTimeCounter > 0)
                {
                    rb.linearVelocity = new Vector3(rb.linearVelocity.x, jumpForce);
    
                    pState.jumping = true;
                }
                else if(!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump"))
                {
                    pState.jumping = true;
    
                    airJumpCounter++;
    
                    rb.linearVelocity = new Vector3(rb.linearVelocity.x, jumpForce);
                }
            }
    
    
            anim.SetBool("Jumping", !Grounded());
        }
    
        void UpdateJumpVariables()
        {
            if (Grounded())
            {
                pState.jumping = false;
                coyoteTimeCounter = coyoteTime;
                airJumpCounter = 0;
            }
            else
            {
                coyoteTimeCounter -= Time.deltaTime;
            }
    
            if (Input.GetButtonDown("Jump"))
            {
                jumpBufferCounter = jumpBufferFrames;
            }
    
            else
            {
                jumpBufferCounter--;
            }
        }        
    
    
    
    }
    ```
    #19054
    Ser Apustaja
    Level 6
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    Hello MOHD YASAR! It looks like you’re encountering a NullReferenceException in your DestroyAfterAnimation script. This error typically occurs when you’re trying to access a component or variable that hasn’t been initialized or assigned.

    In your DestroyAfterAnimation script, you’re trying to get the Animator component and immediately access its current state length in the Start method. However, if the Animator component is not attached to the same GameObject as the DestroyAfterAnimation script, you’ll get a NullReferenceException.

    Here’s how you can fix it:

    1. Ensure the Animator Component is Present: Make sure that the GameObject to which the DestroyAfterAnimation script is attached also has an Animator component. If it doesn’t, you need to add one or ensure that the script is attached to the correct GameObject.

    2. Check for Null Reference: You can add a null check to ensure that the Animator component is not null before trying to access it. Here’s an updated version of your DestroyAfterAnimation script:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class DestroyAfterAnimation : MonoBehaviour
    {
        void Start()
        {
            Animator animator = GetComponent();
            if (animator != null)
            {
                Destroy(gameObject, animator.GetCurrentAnimatorStateInfo(0).length);
            }
            else
            {
                Debug.LogError("Animator component not found on " + gameObject.name);
            }
        }
    }

    With this change, if the Animator component is missing, you’ll get a clear error message in the console instead of a NullReferenceException.

    1. Check Animation States: If the Animator is present but the animation state is not set correctly, it might also lead to issues. Make sure that the animation you want to destroy the GameObject after is the one currently playing.

    2. Debugging: If you’re still having issues, you can add more debug logs to see what is happening at runtime. For example, log the current state of the animator to see if it’s transitioning correctly.

    Let me know if you need further assistance! Happy coding!

Viewing 2 posts - 1 through 2 (of 2 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: