Forum begins after the advertisement:


[Part 6] Repititive NullReferenceException error

Home Forums Video Game Tutorial Series Creating a Metroidvania in Unity [Part 6] Repititive NullReferenceException error

Viewing 15 posts - 1 through 15 (of 22 total)
  • Author
    Posts
  • #13928
    Pete
    Participant

    Hi, I have a trouble on part 6.

    I just followed “Camera Bounds” & “Dynamic Camera Y Damping” and when I try to run the game, it just pauses and there are repetitive error msg on console.

    NullReferenceException: Object reference not set to an instance of an object
    SceneTransition.Start () (at Assets/Scripts/SceneTransition.cs:27)

    NullReferenceException: Object reference not set to an instance of an object
    PlayerController.UpdateCameraYDampForPlayerFall () (at Assets/Scripts/PlayerController.cs:253)
    PlayerController.Update () (at Assets/Scripts/PlayerController.cs:184)

    NullReferenceException: Object reference not set to an instance of an object
    PlayerController.UpdateCameraYDampForPlayerFall () (at Assets/Scripts/PlayerController.cs:258)
    PlayerController.Update () (at Assets/Scripts/PlayerController.cs:184)

    I don’t know how to deal with “NUllReferenceException” error.

    this is my error console img below.

    “Scenetransition.cs”

    public class SceneTransition : MonoBehaviour
    {
        [SerializeField] private string transitionTo; //Represents the scene to transition to
    
        [SerializeField] private Transform startPoint; //Defines the player's entry point in the scene
    
        [SerializeField] private Vector2 exitDirection; //Specifies the direction for the player's exit
    
        [SerializeField] private float exitTime; //Determines the time it takes for the player to exit the scene transition
    
        // Start is called before the first frame update
        private void Start()
        {
            if (GameManager.Instance.transitionedFromScene == transitionTo)
            {
                PlayerController.Instance.transform.position = startPoint.position;
    
                StartCoroutine(PlayerController.Instance.WalkIntoNewScene(exitDirection, exitTime));
            }
            
            StartCoroutine(UIManager.Instance.sceneFader.Fade(SceneFader.FadeDirection.Out));
        }
    
        private void OnTriggerEnter2D(Collider2D _other)
        {
            if (_other.CompareTag("Player"))
            {
                GameManager.Instance.transitionedFromScene = SceneManager.GetActiveScene().name;
    
                PlayerController.Instance.pState.cutscene = true;
    
                SceneManager.LoadScene(transitionTo);
    
                StartCoroutine(UIManager.Instance.sceneFader.FadeAndLoadScene(SceneFader.FadeDirection.In, transitionTo));
            }
        }
    }
    

    “PlayerController.cs”

    
    void Update()
    {
        if (pState.cutscene) return;
    
        GetInputs();
        UpdateJumpVariables();
        UpdateCameraYDampForPlayerFall();
        RestoreTimeScale();
    
        if (pState.dashing) return;
        Flip();
        Move();
        Jump();
        StartDash();
        Attack();
        FlashWhileInvincible();
        Heal();
        CastSpell();
    }
    void UpdateCameraYDampForPlayerFall() 
    {
        //if falling past a certain speed threshold
        if(rb.velocity.y < playerFallSpeedThreshold && !CameraManager.Instance.isLerpingYDamping && !CameraManager.Instance.hasLerpedYDamping)
        {
            StartCoroutine(CameraManager.Instance.LerpYDamping(true));
        }
        //if standing still or moving up
        if(rb.velocity.y >= 0 && !CameraManager.Instance.isLerpingYDamping && CameraManager.Instance.hasLerpedYDamping)
        {
            //reset camera function
            CameraManager.Instance.hasLerpedYDamping = false;
            StartCoroutine(CameraManager.Instance.LerpYDamping(false));
        }
    }
    
    #13932
    Terence
    Keymaster

    Hi Pete, for the SceneFader, can you check this topic and see if it fixes your issue? https://blog.terresquall.com/community/topic/part-5-my-scenefader-cannot-function/

    I’ll need you to bold the line the error is occurring on for your PlayerController script. The null reference exception is specific to certain lines.

    You may also find this video useful:

    #13938
    Pete
    Participant

    Thanks for your reply.

    But blog.terresquall.com/community/topic/part-5-my-scenefader-cannot-function/ this case doesn’t work for me…

    and try to solve with Youtube video, it also doesn’t work…

    so i’ll bold all the line the error is occuring.

    “SceneTransition.cs”

    using System.Collections;
    using System.Collections.Generic;
    using UnityEditor.Build.Content;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class SceneTransition : MonoBehaviour
    {
    [SerializeField] private string transitionTo; //Represents the scene to transition to
    
    [SerializeField] private Transform startPoint; //Defines the player's entry point in the scene
    
    [SerializeField] private Vector2 exitDirection; //Specifies the direction for the player's exit
    
    [SerializeField] private float exitTime; //Determines the time it takes for the player to exit the scene transition
    
    // Start is called before the first frame update
    private void Start()
    {
    if (GameManager.Instance.transitionedFromScene == transitionTo)
    {
    PlayerController.Instance.transform.position = startPoint.position;
    
    StartCoroutine(PlayerController.Instance.WalkIntoNewScene(exitDirection, exitTime));
    
    }
    
    StartCoroutine(UIManager.Instance.sceneFader.Fade(SceneFader.FadeDirection.Out));
    }
    
    private void OnTriggerEnter2D(Collider2D _other)
    {
    if (_other.CompareTag("Player"))
    {
    GameManager.Instance.transitionedFromScene = SceneManager.GetActiveScene().name;
    
    PlayerController.Instance.pState.cutscene = true;
    
    SceneManager.LoadScene(transitionTo);
    
    StartCoroutine(UIManager.Instance.sceneFader.FadeAndLoadScene(SceneFader.FadeDirection.In, transitionTo));
    }
    }
    }

    “PlayerController.cs”

    void Update()
    {
    if (pState.cutscene) return;
    
    GetInputs();
    UpdateJumpVariables();
    UpdateCameraYDampForPlayerFall();
    RestoreTimeScale();
    
    if (pState.dashing) return;
    Flip();
    Move();
    Jump();
    StartDash();
    Attack();
    FlashWhileInvincible();
    Heal();
    CastSpell();
    }
    
    void UpdateCameraYDampForPlayerFall()
    {
    //if falling past a certain speed threshold
    if(rb.velocity.y < playerFallSpeedThreshold && !CameraManager.Instance.isLerpingYDamping && !CameraManager.Instance.hasLerpedYDamping)
    {
    StartCoroutine(CameraManager.Instance.LerpYDamping(true));
    }
    //if standing still or moving up
     if(rb.velocity.y >= 0 && !CameraManager.Instance.isLerpingYDamping && CameraManager.Instance.hasLerpedYDamping)
    {
    //reset camera function
    CameraManager.Instance.hasLerpedYDamping = false;
    StartCoroutine(CameraManager.Instance.LerpYDamping(false));
    }
    }
    #13940
    Joseph Tang
    Moderator

    In regards to the camera, can you check if your Camera parent or any object has the CameraManager.cs script on it? I feel that likely the errors in the PlayerController.cs is a separate issue where it cannot find an instance of the CameraManager.cs

    As for your SceneTransition, check that your Canvas Prefab has a UIManager.cs attached to it & the “Scene Fader” assigned appropriately to it. Then ensure that the SceneFader game object in the Canvas is set to Active as an inactive one will be taken as a null.

    Otherwise, if both situations don’t work, could you taking some screenshots of the inspector of your UIManager, Player, SceneTransition inspectors & a video or console of what happens when you transition scenes?

    As a side note, I noticed that your SceneTransition.cs calls SceneManager.LoadScene(transitionTo); in the private void OnTriggerEnter2D(Collider2D _other) method before the StartCoroutine. You should not need the LoadScene() code itself as the coroutine you are casting will activate both the fade and LoadScene() already.

    #13954
    Pete
    Participant

    I think that i better to show you my situation with screenshots and video

    and in canvas prefab, I can’t attach SceneFader.cs on UIManager…

    “Player Inspector”



    “UIManager Inspector”

    “SceneTransition Inspector”

    “Error Console”


    #13955
    Joseph Tang
    Moderator

    Hi sorry, but I’ll need more videos, particularly, you showing how the Canvas Prefab inspector is like while in game + Moving out of the camera bounds + scene transitions. You can take one video straight, selecting different objects to show their insectors.

    From the looks of the normal inspectors, either there is no SceneFader set on your UIManager.cs, or it will be automatically set by a SceneFader.instance if there is one in the scene.

    #13957
    Pete
    Participant

    thanks for your reply Joseph!

    You mean this one-take video?

    and I want to show scene transitioning but when I start game, the character’s movement is not working.

    So the only things I can show you in this video is Inspectors.

    #13961
    Joseph Tang
    Moderator

    As can be seen in the video, your Canvas has nothing set as it’s Scene Fader.

    As for the fact that you cannot move, I believe something went wrong with your RigidBody2D which is also causing the NullReferenceException Errors for your UpdateCameraYDampForPlayerFall() method.

    Can you copy and paste the entire code for your UIManager.cs & your PlayerController.cs?

    At the same time, check if the Scene Fader game object under your Canvas has a SceneFader.cs script on it.

    #13963
    Pete
    Participant

    Here’s my code

    “UIManager.cs”

    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class UIManager : MonoBehaviour
    {
        public static UIManager Instance;
    
        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
            DontDestroyOnLoad(gameObject);
        }
    
        public SceneFader sceneFader;
    
        private void Start()
        {
            sceneFader = GetComponentInChildren<SceneFader>();
        }
    }
    

    “PlayerController.cs”

    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UIElements;
    using UnityEngine.UI;
    using Unity.VisualScripting;
    
    public class PlayerController : MonoBehaviour
    {
        [Header("Horizontal Movement Settings:")]
        [SerializeField] private float walkSpeed = 1; //sets the players movement speed on the ground
        [Space(5)]
    
        [Header("Vertical Movement Settings")]
        [SerializeField] private float jumpForce = 45f; //sets how hight the player can jump
    
        private int jumpBufferCounter = 0; //stores the jump button input
        [SerializeField] private int jumpBufferFrames; //sets the max amount of frames the jump buffer input is stored
    
        private float coyoteTimeCounter = 0; //stores the Grounded() bool
        [SerializeField] private float coyoteTime; ////sets the max amount of frames the Grounded() bool is stored
    
        private int airJumpCounter = 0; //keeps track of how many times the player has jumped in the air
        [SerializeField] private int maxAirJumps; //the max no. of air jumps
    
        private float gravity; //stores the gravity scale at start
        [Space(5)]
    
        [Header("Ground Check Settings:")]
        [SerializeField] private Transform groundCheckPoint; //point at which ground check happens
        [SerializeField] private float groundCheckY = 0.2f; //how far down from ground chekc point is Grounded() checked
        [SerializeField] private float groundCheckX = 0.5f; //how far horizontally from ground chekc point to the edge of the player is
        [SerializeField] private LayerMask whatIsGround; //sets the ground layer
        [Space(5)]
    
        [Header("Dash Settings")]
        [SerializeField] private float dashSpeed; //speed of the dash
        [SerializeField] private float dashTime; //amount of time spent dashing
        [SerializeField] private float dashCooldown; //amount of time between dashes
        [SerializeField] GameObject dashEffect;
        private bool canDash = true, dashed;
        [Space(5)]
    
        [Header("Attack Settings:")]
        [SerializeField] private Transform SideAttackTransform; //the middle of the side attack area
        [SerializeField] private Vector2 SideAttackArea; //how large the area of side attack is
    
        [SerializeField] private Transform UpAttackTransform; //the middle of the up attack area
        [SerializeField] private Vector2 UpAttackArea; //how large the area of side attack is
    
        [SerializeField] private Transform DownAttackTransform; //the middle of the down attack area
        [SerializeField] private Vector2 DownAttackArea; //how large the area of down attack is
    
        [SerializeField] private LayerMask attackableLayer; //the layer the player can attack and recoil off of
    
        private float timeBetweenAttack, timeSinceAttck;
    
        [SerializeField] private float damage; //the damage the player does to an enemy
    
        [SerializeField] private GameObject slashEffect; //the effect of the slashs
    
        bool restoreTime;
        float restoreTimeSpeed;
        [Space(5)]
    
      
    
        [Header("Recoil Settings:")]
        [SerializeField] private int recoilXSteps = 5; //how many FixedUpdates() the player recoils horizontally for
        [SerializeField] private int recoilYSteps = 5; //how many FixedUpdates() the player recoils vertically for
    
        [SerializeField] private float recoilXSpeed = 100; //the speed of horizontal recoil
        [SerializeField] private float recoilYSpeed = 100; //the speed of vertical recoil
    
        private int stepsXRecoiled, stepsYRecoiled; //the no. of steps recoiled horizontally and verticall
        [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)]
    
        float healTimer;
        [SerializeField] float timeToHeal;
        [Space(5)]
    
        [Header("Mana Settings")]
        [SerializeField] UnityEngine.UI.Image manaStorage;
    
        [SerializeField] float mana;
        [SerializeField] float manaDrainSpeed;
        [SerializeField] float manaGain;
        [Space(5)]
    
        [Header("Spell Settings")]
        [SerializeField] float manaSpellCost = 0.3f;
        [SerializeField] float timeBetweenCast = 0.5f;
        [SerializeField] float spellDamage; //upspellexplosion and downspellexplosion only
        [SerializeField] float downSpellForce; //desolate dive only
        //spell cast objects
        [SerializeField] GameObject sideSpellFireball;
        [SerializeField] GameObject upSpellFireball;
        [SerializeField] GameObject downSpellFireball;
        float timeSinceCast;
        float castOrHealthtimer;
        [Space(5)]
    
        [Header("Camera Stuff")]
        [SerializeField] private float playerFallSpeedThreshold = -10;
    
        [HideInInspector] public PlayerStateList pState;
        [HideInInspector] public Rigidbody2D rb;
        private Animator anim;
        private SpriteRenderer sr;
    
        //Input Variables
        private float xAxis, yAxis;
        private bool attack = false;
        private bool canFlash = true;
    
        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.red;
            Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea);
            Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea);
            Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea);
        }
    
        // Update is called once per frame
        void Update()
        {
            if (pState.cutscene) return;
    
            GetInputs();
            UpdateJumpVariables();
            UpdateCameraYDampForPlayerFall();
            RestoreTimeScale();
    
            if (pState.dashing) return;
            Flip();
            Move();
            Jump();
            StartDash();
            Attack();
            FlashWhileInvincible();
            Heal();
            CastSpell();
        }
    
        private void OnTriggerEnter2D(Collider2D _other) //for up and down cast spell
        {
            if(_other.GetComponent<Enemy>() != null && pState.casting)
            {
                _other.GetComponent<Enemy>().EnemyGetsHit(spellDamage, (_other.transform.position - transform.position).normalized, -recoilYSpeed); 
            }
        }
    
        private void FixedUpdate()
        {
            if (pState.cutscene) return;
    
            if (pState.dashing) return;
            Recoil();
        }
    
        void GetInputs()
        {
            xAxis = Input.GetAxisRaw("Horizontal");
            yAxis = Input.GetAxisRaw("Vertical");
            attack = Input.GetButtonDown("Attack");
    
            if(Input.GetButtonDown("Cast/Heal"))
            {
                castOrHealthtimer += Time.deltaTime;
            }
            else
            {
                castOrHealthtimer = 0;
            }
        }
    
        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 UpdateCameraYDampForPlayerFall() 
        {
            //if falling past a certain speed threshold
            if(rb.velocity.y < playerFallSpeedThreshold && !CameraManager.Instance.isLerpingYDamping && !CameraManager.Instance.hasLerpedYDamping)
            {
                StartCoroutine(CameraManager.Instance.LerpYDamping(true));
            }
            //if standing still or moving up
            if(rb.velocity.y >= 0 && !CameraManager.Instance.isLerpingYDamping && CameraManager.Instance.hasLerpedYDamping)
            {
                //reset camera function
                CameraManager.Instance.hasLerpedYDamping = false;
                StartCoroutine(CameraManager.Instance.LerpYDamping(false));
            }
        }
    
        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;
            int _dir = pState.lookingRight ? 1 : -1;
            rb.velocity = new Vector2(_dir * 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;
        }
    
        public IEnumerator WalkIntoNewScene(Vector2 _exitDir, float _delay)
        {
            //If exit direction is upwards
            if (_exitDir.y != 0)
            {
                rb.velocity = jumpForce * _exitDir;
            }
    
            //If exit direction requires horizontal movement
            if (_exitDir.x != 0)
            {
                xAxis = _exitDir.x > 0 ? 1 : -1;
    
                Move();
            }
    
            Flip();
            yield return new WaitForSeconds(_delay);
            pState.cutscene = false;
        }
    
        void Attack()
        {
            timeSinceAttck += Time.deltaTime;
            if (attack && timeSinceAttck >= timeBetweenAttack)
            {
                timeSinceAttck = 0;
                anim.SetTrigger("Attacking");
    
                if (yAxis == 0 || yAxis < 0 && Grounded())
                {
                    int _recoilLeftOrRight = pState.lookingRight ? 1 : -1;
    
                    Hit(SideAttackTransform, SideAttackArea, ref pState.recoilingX, Vector2.right * _recoilLeftOrRight, recoilXSpeed);
                    Instantiate(slashEffect, SideAttackTransform);
                }
                else if (yAxis > 0)
                {
                    Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingY, Vector2.up, recoilYSpeed);
                    SlashEffectAtAngle(slashEffect, 80, UpAttackTransform);
                }
                else if (yAxis < 0 && !Grounded())
                {
                    Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, Vector2.down, recoilYSpeed);
                    SlashEffectAtAngle(slashEffect, -90, DownAttackTransform);
                }
            }
    
        }
        void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilBool, Vector2 _recoilDir, float _recoilStrength)
        {
            Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer);
    
            if (objectsToHit.Length > 0)
            {
                _recoilBool = true;
            }
            for (int i = 0; i < objectsToHit.Length; i++)
            {
                if (objectsToHit[i].GetComponent<Enemy>() != null)
                {
                    objectsToHit[i].GetComponent<Enemy>().EnemyGetsHit(damage, _recoilDir, _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 Vector2(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;
        }
    
        IEnumerator Flash()
        {
            sr.enabled = !sr.enabled;
            canFlash = false;
            yield return new WaitForSeconds(0.1f);
            canFlash = true;
        }
    
        void FlashWhileInvincible()
        {
            if (pState.invincible)
            {
                if (Time.timeScale > 0.2 && canFlash)
                {
                    StartCoroutine(Flash());
                }
            }
            else
            {
                sr.enabled = true;
            }
        }
        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;
            if (_delay > 0)
            {
                StopCoroutine(StartTimeAgain(_delay));
                StartCoroutine(StartTimeAgain(_delay));
            }
            else
            {
                restoreTime = true;
            }
            Time.timeScale = _newTimeScale;
        }
        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("Cast/Heal") && castOrHealthtimer >  0.05f && 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;
                }
                //drain mana
                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.GetButtonUp("Cast/Heal") && castOrHealthtimer <= 0.05f && 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 down until grounded
            if (downSpellFireball.activeInHierarchy)
            {
                rb.velocity += downSpellForce * Vector2.down;
            }
        }
    
        IEnumerator CastCoroutine()
        {
            anim.SetBool("Casting", true);
            yield return new WaitForSeconds(0.09f);
    
            //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; //if facing right, fireball continues as per normal
                }
                else
                {
                    _fireBall.transform.eulerAngles = new Vector2(_fireBall.transform.eulerAngles.x, 180);
                    //if not facing right, rotate the fireball 180 degree
                }
                pState.recoilingX = true;
            }
    
            //up cast
            else if (yAxis > 0)
            {
                Instantiate(upSpellFireball, transform);
                rb.velocity = Vector2.zero;
            }
    
            //down cast
            else if (yAxis < 0 && !Grounded())
            {
                downSpellFireball.SetActive(true);
            }
    
            Mana -= manaSpellCost;
            yield return new WaitForSeconds(0.09f);
            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 (jumpBufferCounter > 0 && coyoteTimeCounter > 0 && !pState.jumping)
            {
                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);
            }
    
            if (Input.GetButtonUp("Jump") && rb.velocity.y > 3)
            {
                rb.velocity = new Vector2(rb.velocity.x, 0);
    
                pState.jumping = false;
            }
    
            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--;
            }
        }
    }
    
    #13964
    Joseph Tang
    Moderator

    For the SceneFader error:
    Add this code under UIManager.cs:

    private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
            DontDestroyOnLoad(gameObject);
            sceneFader = GetComponentInChildren();
        }

    As for your movement and camera issue. I’ll need to check so give me a moment.

    #13965
    Joseph Tang
    Moderator

    This is quite a confusing situation,
    So far it seems your code is correct. I’ve even used the code you’ve provided and i’ve had no errors so far.
    So unless some other code is messing it all up, which i doubt, the only issue should be your scene/Camera setup. But why your character cannot move I’m not sure of.

    I’ll try to find a solution but for now, I can’t confidently pin the cause of the issue.

    #13966
    Pete
    Participant

    Thanks for your help Joseph.

    I want to tell you that I can move character until “[Part6] Camera Bounds” but after I follow “Dynamic Camera Y Damping”, I can’t move my character.

    I tried to find solution from there, but I couldn’t…

    I hope this problem to be solved soon.

    #13967
    Joseph Tang
    Moderator

    Could you send your CameraManager.cs? I have a theory that the methods aren’t there or are named differently, causing the error.

    Furthermore, I believe the reason you can’t move is because your Update() is failing to call your UpdateCameraYDampForPlayerFall() method and thus cannot get to Move() in your code.

    #13968
    Pete
    Participant

    Sure here’s the code

    using System.Collections;
    using System.Collections.Generic;
    using Cinemachine;
    using UnityEngine;
    
    public class CameraManager : MonoBehaviour
    {
        [SerializeField] CinemachineVirtualCamera[] allVirtualCameras;
        private CinemachineVirtualCamera currentCamera;
        private CinemachineFramingTransposer framingTransposer;
    
        [Header("Y Damping Settings for Player Jump/Fall: ")]
        [SerializeField] private float panAmount = 0.1f;
        [SerializeField] private float panTime = 0.2f;
        public float playerFallSpeedThreshold = -10;
        public bool isLerpingYDamping;
        public bool hasLerpedYDamping;
    
        private float normalYDamp;
    
        public static CameraManager Instance { get; private set; }
    
        private void Awake() 
        {
            if(Instance = null)
            {
                Instance = this;
            }
    
            for(int i = 0; i < allVirtualCameras.Length; i++)
            {
                if (allVirtualCameras[i].enabled) 
                {
                    currentCamera = allVirtualCameras[i];
    
                    framingTransposer =  currentCamera.GetCinemachineComponent<CinemachineFramingTransposer>();
                }
            }
    
            normalYDamp = framingTransposer.m_YDamping;
        }
    
        private void Start() 
        {
            for (int i = 0; i < allVirtualCameras.Length; i++)
            {
                allVirtualCameras[i].Follow = PlayerController.Instance.transform;
            }
        }
    
        public void SwapCamera(CinemachineVirtualCamera _newCam) 
        {
            currentCamera.enabled = false;
    
            currentCamera = _newCam;
    
            currentCamera.enabled = true;
        }
    
        public IEnumerator LerpYDamping(bool _isPlayerFalling)
        { 
            isLerpingYDamping = true;
            //take start y damp amount
            float _startYDamp = framingTransposer.m_YDamping;
            float _endYDamp = 0;
            //determine end damp amount
            if (_isPlayerFalling) 
            {
                _endYDamp = panAmount;
                hasLerpedYDamping = true;
            }
            else 
            {
                _endYDamp = normalYDamp;
            }
            //lerp panAmount
            float _timer = 0;
            while (_timer < panTime) 
            {
                _timer += Time.deltaTime;
                float _lerpedPanAmount = Mathf.Lerp(_startYDamp, _endYDamp, (_timer / panTime));
                framingTransposer.m_YDamping = _lerpedPanAmount;
                yield return null;
            }
            isLerpingYDamping = false;
        }
    }
    #13969
    Joseph Tang
    Moderator

    Okay, so nothing appears to be wrong with your code, let’s try to find what isn’t being set then:

    1) Replace rb.velocity.y with values [0] & [1] (Checking if rb is the nullreference)
    2) Put the code print(CameraManager.Instance); (Checking if the correct cameramanager is found)
    In your PlayerController.cs,

    void UpdateCameraYDampForPlayerFall()
        {
            print(CameraManager.Instance);
            //if falling past a certain speed threshold
            if (rb.velocity.y 0 < playerFallSpeedThreshold && !CameraManager.Instance.isLerpingYDamping && !CameraManager.Instance.hasLerpedYDamping)
            {
                StartCoroutine(CameraManager.Instance.LerpYDamping(true));
            }
            //if standing stil or moving up
            if (rb.velocity.y 1 >= 0 && !CameraManager.Instance.isLerpingYDamping && CameraManager.Instance.hasLerpedYDamping)
            {
                //reset camera function
                CameraManager.Instance.hasLerpedYDamping = false;
                StartCoroutine(CameraManager.Instance.LerpYDamping(false));
            }
        }

    If change (1) returns a nullreference, then your CameraManager cannot be found. If (2) returns the correct name, then your cameramanager can be found.

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

Go to Login Page →


Advertisement below: