Forum begins after the advertisement:


[Part 5] nullpointer exception when adding tiles

Home Forums Video Game Tutorial Series Creating a Metroidvania in Unity [Part 5] nullpointer exception when adding tiles

Viewing 8 posts - 1 through 8 (of 8 total)
  • Author
    Posts
  • #14214
    Ethan
    Participant

    been adding some new tiles to make my level look good and when ive gone to add some tiles its thrown a null pointer exception in the player controller code . Ive pasted the code down below but this is what it says in the console

    NullReferenceException: Object reference not set to an instance of an object
    PlayerController.Start () (at Assets/Scripts/PlayerController.cs:131)
    using System.Collections;
    using System.Collections.Generic;
    using Unity.Mathematics;
    using Unity.VisualScripting;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class PlayerController : MonoBehaviour
    {
        [Header("Horizontal Movement")]
        [SerializeField] private float walkSpeed = 20;
        [Space(5)]
    
        [Header("vertical movement")]
        [SerializeField] private float jumpForce = 35f;
        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;
        [SerializeField] GameObject dashEffect;
        [Space(5)]
    
        [Header("Attack Settings")]
        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;
        [Space(5)]
    
        [Header("Recoil")]
        [SerializeField] int recoilXSteps = 5;
        [SerializeField] int recoilYSteps = 5;
        [SerializeField] float recoilXSpeed = 100;
        [SerializeField] float recoilYSpeed = 100;
        int stepsXRecoiled, stepsYRecoiled;
        [Space(5)]
    
        [Header("Health Settings")]
        public int health;
        public int maxHealth;
        [SerializeField] GameObject bloodSpurt;
        [SerializeField] float hitFlashSpeed;
        public delegate void OnHealthChangedDelegate();
        [HideInInspector] public OnHealthChangedDelegate OnHealthChangedCallback;
        [Space(5)]
    
        bool restoreTime;
        float restoreTimeSpeed;
        [Space(5)]
    
        [Header("Healing")]
        float healTimer;
        [SerializeField] float timeToHeal;
        [Space(5)]
    
        [Header("Mana Settings")]
        [SerializeField] Image manaStorage;
        [SerializeField] float mana;
        [SerializeField] float manaDrainSpeed;
        [SerializeField] float manaGain;
        [Space(5)]
    
        [Header("Spell Casting")]
        [SerializeField] float manaSpellCost = 0.3f;
        [SerializeField] float timeBetweenCast = 0.5f;
        float timeSinceCast;
        [SerializeField] float spellDamage;//upspell explosion and downspell fireball
        [SerializeField] float downSpellForce; //dive only
        //spell cast objects
        [SerializeField] GameObject sideSpellFireball;
        [SerializeField] GameObject upSpellExplosion;
        [SerializeField] GameObject downSpellFireball;
        [Space(5)]
    
        [HideInInspector] public PlayerStateList pState;
        private Rigidbody2D rb;
        private SpriteRenderer sr;
        private float xAxis,yAxis;
        private float gravity;
        Animator anim;
        private bool canDash = true;
        private bool dashed;
    
        public static PlayerController Instance;
    
        private void Awake()
        {
            if(Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
            DontDestroyOnLoad(gameObject);
        }
    
        // Start is called before the first frame update
        void Start()
        {
            pState = GetComponent<PlayerStateList>();   
    
            rb = GetComponent<Rigidbody2D>();
    
            sr = GetComponent<SpriteRenderer>();
    
            anim = GetComponent<Animator>();
    
            gravity = rb.gravityScale;
            
            Mana = mana;
            manaStorage.fillAmount = Mana;
    
            Health = maxHealth;
        }
        private void OnDrawGizmos()
        {
            Gizmos.color = Color.yellow;
            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();
            RestoreTimeScale();
            FlashWhileInvincible();
            Heal();
            CastSpell();
        }
    
        private void OnTriggerEnter2D(Collider2D _other)
        {
            if (_other.GetComponent<Enemy>() != null && pState.casting)
            {
                _other.GetComponent<Enemy>().EnemyHit(spellDamage, (_other.transform.position - transform.position).normalized, -recoilYSpeed);
            }
        }
    
        private void FixedUpdate()
        {
            if(pState.dashing) return;
            Recoil();
        }
    
        void GetInputs()
        {
            xAxis = Input.GetAxisRaw("Horizontal");
            yAxis = Input.GetAxisRaw("Vertical");
            attack = Input.GetButtonDown("Attack");
    
        }
    
        void Flip()
        {
            if(xAxis < 0)
            {
                transform.localScale = new Vector2(-1, transform.localScale.y);
                pState.lookingRight = false;
            }
            else if(xAxis > 0) 
            {
                transform.localScale = new Vector2(1, transform.localScale.y);
                pState.lookingRight = true;
            }
        }
    
        private void Move()
        {
            rb.velocity = new Vector2(walkSpeed * xAxis, rb.velocity.y);
            anim.SetBool("Walking", rb.velocity.x != 0 && Grounded());
        }
        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.velocity = new Vector2(transform.localScale.x * dashSpeed, 0);
            if (Grounded()) Instantiate(dashEffect, transform);
            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, ref pState.recoilingX,recoilXSpeed);
                    Instantiate(slashEffect, SideAttackTransform);
                }
                else if(yAxis>0)
                {
                    Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingY, recoilYSpeed);
                    SlashEffectAtAngle(slashEffect, 90, UpAttackTransform);
                }
                else if (yAxis < 0 && !Grounded())
                {
                    Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, recoilYSpeed);
                    SlashEffectAtAngle(slashEffect,-90,DownAttackTransform);
                }
            }
        }
    
        void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilDir, float _recoilStrength)
        {
            Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer);
    
            if(objectsToHit.Length > 0 )
            {
                _recoilDir = true;
            }
            for(int i=0; i<objectsToHit.Length; i++)
            {
                if (objectsToHit[i].GetComponent<Enemy>() != null)
                {
                    objectsToHit[i].GetComponent<Enemy>().EnemyHit(damage,(transform.position- objectsToHit[i].transform.position).normalized,_recoilStrength);
    
                    if (objectsToHit[i].CompareTag("Enemy"))
                    {
                        Mana += manaGain;
                    }
                }
            }
        }
    
        void SlashEffectAtAngle(GameObject _slashEffect, int _effectAngle,Transform _attackTransform)
        {
            _slashEffect = Instantiate(_slashEffect, _attackTransform);
            _slashEffect.transform.eulerAngles = new Vector3(0, 0, _effectAngle);
            _slashEffect.transform.localScale = new Vector3(transform.localScale.x, transform.localScale.y);
        }
    
        void Recoil()
        {
    
            if(pState.recoilingX)
            {
                if(pState.lookingRight)
                {
                    rb.velocity = new Vector2(-recoilXSpeed, 0);
                }
                else
                {
                    rb.velocity = new Vector2(recoilXSpeed, 0);
                }
            }
            if(pState.recoilingY)
            {
                rb.gravityScale = 0;
                if (yAxis < 0)
                {
                    rb.velocity = new Vector2(rb.velocity.x, recoilYSpeed);
                }
                else
                {
                    rb.velocity=new Vector2(rb.velocity.x, -recoilYSpeed);
                }
                airJumpCounter = 0;
            }
            else
            {
                rb.gravityScale = gravity;
            }
            //stop recoil
            if(pState.recoilingX && stepsXRecoiled < recoilXSteps)
            {
                stepsXRecoiled++;
            }
            else
            {
                StopRecoilX();
            }
            if(pState.recoilingY && stepsYRecoiled < recoilYSteps)
            {
                stepsYRecoiled++;
            }
            else
            {
                StopRecoilY();
            }
            if(Grounded())
            {
                StopRecoilY();
            }
        }
    
        void StopRecoilX()
        {
            stepsXRecoiled = 0;
            pState.recoilingX = false;
        }
    
        void StopRecoilY()
        {
            stepsYRecoiled = 0;
            pState.recoilingY = false;
        }
        public void TakeDamage(float _damage)
        {
            Health -= Mathf.RoundToInt(_damage);
            StartCoroutine(StopTakingDamage());
        }
    
        IEnumerator StopTakingDamage()
        {
            pState.invincible = true;
            GameObject _bloodSpurtParticles = Instantiate(bloodSpurt, transform.position, quaternion.identity);
            Destroy(_bloodSpurtParticles,1.5f);
            anim.SetTrigger("TakeDamage");
            yield return new WaitForSeconds(1f);
            pState.invincible=false;
        }
        void FlashWhileInvincible()
        {
            sr.material.color = pState.invincible ? Color.Lerp(Color.white, Color.black, Mathf.PingPong(Time.time * hitFlashSpeed, 1.0f)): Color.white;
        }
        void RestoreTimeScale()
        {
            if(restoreTime)
            {
                if(Time.timeScale <1)
                {
                    Time.timeScale += Time.deltaTime * restoreTimeSpeed;
                }
                else
                {
                    Time.timeScale = 1;
                    restoreTime = false;
                }
            }
        }
        public void HitStopTime(float _newTimeScale, int _restoreSpeed, float _delay)
        {
            restoreTimeSpeed = _restoreSpeed;
            Time.timeScale = _newTimeScale;
    
            if(_delay > 0)
            {
                StopCoroutine(StartTimeAgain(_delay));
                StartCoroutine(StartTimeAgain(_delay));
            }
            else
            {
                restoreTime = true;
            }
        }
        IEnumerator StartTimeAgain(float _delay)
        {
            restoreTime = true;
            yield return new WaitForSeconds(_delay);
        }
        public int Health
        {
            get { return health; }
            set
            {
                if(health != value)
                {
                    health = Mathf.Clamp(value, 0, maxHealth);
    
                    if(OnHealthChangedCallback != null)
                    {
                        OnHealthChangedCallback.Invoke();
                    }
                }
            }
        }
    
        void Heal()
        {
             if(Input.GetButton("Healing")&& Health < maxHealth && Mana >0 && !pState.jumping && !pState.dashing)
            {
                pState.healing = true;
                anim.SetBool("Healing", true);
    
                //healing
                healTimer += Time.deltaTime;
                if(healTimer >= timeToHeal)
                {
                    Health++;
                    healTimer = 0;
                }
                Mana -= Time.deltaTime * manaDrainSpeed;
            }
             else
            {
               pState.healing= false;
                anim.SetBool("Healing", false);
                healTimer = 0;
            }
            
        }
        float Mana
        {
            get { return mana; }
            set
            {
                //if mana stats change
                if (mana != value)
                {
                    mana = Mathf.Clamp(value, 0, 1);
                    manaStorage.fillAmount = Mana;
                }
            }
        }
    
        void CastSpell()
        {
            if(Input.GetButton("CastSpell")&& timeSinceCast >= timeBetweenCast && Mana >= manaSpellCost)
            {
                pState.casting = true;
                timeSinceCast = 0;
                StartCoroutine(CastCoroutine());
            }
            else
            {
                timeSinceCast += Time.deltaTime;
            }
            if(Grounded())
            {
                //disable downspell if on the ground
                downSpellFireball.SetActive(false);
            }
            //if down spell is active,force player downwards till it reaches a grounded layer
            if(downSpellFireball.activeInHierarchy)
            {
                rb.velocity += downSpellForce * Vector2.down;
            }
    
        }
    
        IEnumerator CastCoroutine()
        {
            anim.SetBool("Casting", true);
            yield return new WaitForSeconds(0.15f);
    
            //side cast
            if(yAxis == 0 || (yAxis <0 && Grounded()))
            {
                GameObject _fireBall= Instantiate(sideSpellFireball, SideAttackTransform.position,Quaternion.identity);
    
                //flip fireball
                if(pState.lookingRight)
                {
                    _fireBall.transform.eulerAngles = Vector3.zero;
                }
                else
                {
                    _fireBall.transform.eulerAngles = new Vector2(_fireBall.transform.eulerAngles.x, 180);//if not looking right rotate the fireball sprite
                }
                pState.recoilingX = true;
            }
            //up cast
            else if(yAxis >0)
            {
                Instantiate(upSpellExplosion, transform);
                rb.velocity = Vector2.zero;
            }
            //down cast
            else if(yAxis <0 && !Grounded())
            {
                downSpellFireball.SetActive(true);
            }
            Mana -= manaSpellCost;
            yield return new WaitForSeconds(0.35f);
            anim.SetBool("Casting", false);
            pState.casting = false;
        }
    
        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.velocity.y > 0)
            {
                rb.velocity = new Vector2(rb.velocity.x, 0);
    
                pState.jumping = false;
            }
            if (!pState.jumping)
            {
                if (jumpBufferCounter >0 && coyoteTimeCounter>0)
                {
                    rb.velocity = new Vector3(rb.velocity.x, jumpForce);
    
                    pState.jumping = true;
                }
                else if(!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump"))
                {
                    pState.jumping = true;
    
                    airJumpCounter++;
    
                    rb.velocity = new Vector3(rb.velocity.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--;
            }
        }
    }
    #14217
    Terence
    Keymaster

    Line 131 seems to be here:

        // Start is called before the first frame update
        void Start()
        {
            pState = GetComponent();   
    
            rb = GetComponent();
    
            sr = GetComponent();
    
            anim = GetComponent();
    
            gravity = rb.gravityScale;
            
            Mana = mana;
            manaStorage.fillAmount = Mana;
    
            Health = maxHealth;
        }

    It looks like your manaStorage variable is not assigned, hence the line becomes null.fillAmount and causes the Null Reference Exception.

    #14219
    Ethan
    Participant

    what do i need to include in the code so that the the variable is assigned ? thanks

    #14224
    Ethan
    Participant

    what do i need to change in my code so that it works ? thank you

    #14225
    Ethan
    Participant

    it keeps duplicating the reply sorry about that no idea why

    #14226
    Ethan
    Participant

    i have the mana storage set on my player controller and its still returning null do you need me to send a video or is there something else that i have missed

    #14232
    Joseph Tang
    Moderator

    Yes, could you send a video of you outside and in the game, with the inspector of the PlayerController.cs, Canvas and the Mana game object?

    #14234
    Ethan
    Participant

    found the issue when adding the objects to the scene it was removing the mana ui image off of the player in the inspector for somereason thanks for the help though :)

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

Go to Login Page →


Advertisement below: