Forum begins after the advertisement:


Scene Transitions Not Working

Home Forums Video Game Tutorial Series Creating a Metroidvania in Unity Scene Transitions Not Working

Viewing 15 posts - 1 through 15 (of 15 total)
  • Author
    Posts
  • #16264
    Ferral Child
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    Hello,

    I am having issues with getting my scene transition to work. As no matter how many times I run into what should be the transition ‘doorway’ to the next scene, nothing happens at all. Any advice would be greatly appreciated!

    Code Below:

    Player Controller

    using System.Collections;
    using System.Collections.Generic;
    
    using UnityEngine;
    
    public class playerController : MonoBehaviour
    {
    
        [SerializeField] private float walkspeed = 1;
    
        [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;
    
        //Ground Check Settings
    
        [SerializeField] private Transform GroundCheckPoint;
        [SerializeField] private float GroundCheckY = 0.2f;
        [SerializeField] private float GroundCheckX = 0.5f;
        [SerializeField] private LayerMask WhatIsGround;
    
        //Dash Settings
    
        [SerializeField] private float dashSpeed;
        [SerializeField] private float dashTime;
        [SerializeField] private float dashCooldown;
       
        //Attack Settings
    
        [SerializeField] private Transform SideAttackTransform, UpAttackTransform, DownAttackTransform;
        [SerializeField] private Vector2 SideAttackArea, UpAttackArea, DownAttackArea;
        [SerializeField] private LayerMask AttackableLayer;
        [SerializeField] private float timeBetweenAttack;
        [SerializeField] private float damage;
    
        private int stepsXRecoiled, stepsYRecoiled;
    
        // Recoil Settings
        
        [SerializeField] private int recoilXSteps = 5; 
        [SerializeField] private int recoilYSteps = 5; 
        [SerializeField] private float recoilXSpeed = 100;
        [SerializeField] private float recoilYSpeed = 100;
    
        //Health Settings
    
        public int health;
       public int maxHealth;
        [SerializeField] GameObject DamagePart;
        [SerializeField] float hitFlashSpeed;
    
        [HideInInspector] public PlayerStateList pState;
        public Rigidbody2D rb;
        private Animator anim;
        private SpriteRenderer sr;
    
        private float xAxis, yAxis;
        private float gravity;
        private bool canDash = true;
        private bool dashed;
    
        private bool attack = false;
        private float timeSinceAttack;
    
        bool restoreTime;
        float restoreTimeSpeed;
    
        public static playerController Instance;
    
        
        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
            Health = maxHealth;
        }
    
        // Start is called before the first frame update
        void Start()
        {
            pState = GetComponent<PlayerStateList>();
            rb = GetComponent<Rigidbody2D>();
            anim = GetComponent<Animator>();
            gravity = rb.gravityScale;
            sr = GetComponent<SpriteRenderer>();
        }
    
        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();
            RestoreTimeScale();
            UpdateJumpVariables();
            if (pState.Dashing) return;
            Flip();
            Move();
            Jump();
            StartDash();
            Attack();
            Recoil();
            FlashWhileInvincible();
        }
    
        private void FixedUpdate()
        {
            if (pState.Dashing || pState.cutscene) 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(-Mathf.Abs(transform.localScale.x), transform.localScale.y);
                pState.lookingRight = false;
            }
            else if (xAxis > 0)
            {
                transform.localScale = new
                    Vector2(Mathf.Abs(transform.localScale.x), 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);
            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)
        {
            pState.invincible = true;
    
            //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.invincible = false;
            pState.cutscene = false;
        }
    
        void Attack()
        {
            timeSinceAttack += Time.deltaTime;
            if(attack && timeSinceAttack >= timeBetweenAttack) 
            {
                timeSinceAttack = 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);
                }
                else if(yAxis > 0)
                {
                    Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingY, Vector2.up, recoilYSpeed);
                }
                else if (yAxis < 0 && !Grounded())
                {
                    Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, Vector2.down, recoilYSpeed);
                }
            }
        }
    
         void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilBool, Vector2 _recoilDir, float _recoilStrength)
        {
            Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, AttackableLayer);
    
            List<Enemy> hitEnemies = new List<Enemy>();
    
            if (objectsToHit.Length > 0)
            {
                _recoilBool = true;
            }
    
            
            for (int i = 0; i < objectsToHit.Length; i++)
            {
                Debug.Log("Hit");
                Enemy e = objectsToHit[i].GetComponent<Enemy>();
    
                if (objectsToHit[i].GetComponent<Enemy>() != null)
                {
                    objectsToHit[i].GetComponent<Enemy>().EnemyHit(damage, _recoilDir, _recoilStrength);
                }
            }
        }
    
        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 _DamagePartParticles = Instantiate(DamagePart, transform.position, Quaternion.identity);
            Destroy(_DamagePartParticles, 1.5f);
            anim.SetTrigger("TakeDamage");
            yield return new WaitForSeconds(1f);
            pState.invincible = false;
        }
    
        void FlashWhileInvincible()
        {
            if (pState.cutscene) return;
            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.unscaledDeltaTime * 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)
        {
            yield return new WaitForSecondsRealtime(_delay);
            restoreTime = true;
        }
    
        public int Health
        {
            get { return health; }
            set
            {
                if (health != value)
                {
                    health = Mathf.Clamp(value, 0, maxHealth);
                }
            }
        }
    
        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; 
            }
    
            anim.SetBool("Jumping", !Grounded());
    
            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);
    
                   
                }
            }
        }
        void UpdateJumpVariables()
        {
            if (Grounded())
            {
                pState.jumping = false;
                CoyoteTimeCounter = CoyoteTime;
                AirJumpCounter = 0;
            }
            else 
            {
                CoyoteTimeCounter -= Time.deltaTime;
            }
            if (Input.GetButtonDown("Jump"))
            {
                JumpBufferCounter = JumpBufferFrames;
            }
            else
            {
                JumpBufferCounter--;
            }
        }
    }

    Game Manager:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class GameManager : MonoBehaviour
    {
        public string transitionedFromScene;
    
        public Vector2 platformingRespawnPoint;
    
        public static GameManager Instance {get; private set;}
    
        private void Awake()
        {
            if(Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
            DontDestroyOnLoad(gameObject);
        }
    
    }
    

    Scene Fader

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;
    
    public class SceneFader : MonoBehaviour
    {
        [SerializeField] public float fadeTime;
    
        private Image fadeOutUIImage;
        public enum FadeDirection
        {
            In,
            Out
        }
    
        private void Awake()
        {
            fadeOutUIImage = GetComponent<Image>();
        }
    
        public IEnumerator Fade(FadeDirection _fadeDirection)
        {
            float _alpha = _fadeDirection == FadeDirection.Out ? 1 : 0;
            float _fadeEndValue = _fadeDirection == FadeDirection.Out ? 0 : 1;
    
            if (_fadeDirection == FadeDirection.Out)
            {
                while (_alpha >= _fadeEndValue)
                {
                    SetColorImage(ref _alpha, _fadeDirection);
    
                    yield return null;
                }
    
                fadeOutUIImage.enabled = false;
            }
            else
            {
                fadeOutUIImage.enabled = true;
    
                while (_alpha <= _fadeEndValue)
                {
                    SetColorImage(ref _alpha, _fadeDirection);
    
                    yield return null;
                }
            }
        }
        public IEnumerator FadeAndLoadScene(FadeDirection _fadeDirection, string _sceneToLoad)
        {
            fadeOutUIImage.enabled = true;
    
            yield return Fade(_fadeDirection);
    
            SceneManager.LoadScene(_sceneToLoad);
        }
    
        void SetColorImage(ref float _alpha, FadeDirection _fadeDirection)
        {
            fadeOutUIImage.color = new Color(fadeOutUIImage.color.r, fadeOutUIImage.color.g, fadeOutUIImage.color.b, _alpha);
    
            _alpha += Time.deltaTime * (1 / fadeTime) * (_fadeDirection == FadeDirection.Out ? -1 : 1);
        }
    }
    

    Scene Transition:

    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class SceneTransition : MonoBehaviour
    {
        [SerializeField] private string transitionTo;
    
        [SerializeField] private Transform startPoint;
    
        [SerializeField] private Vector2 exitDirection;
    
        [SerializeField] private float exitTime;
    
        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;
                playerController.Instance.pState.invincible = true;
    
                StartCoroutine(UIManager.Instance.sceneFader.FadeAndLoadScene(SceneFader.FadeDirection.In, transitionTo));
            }
        }
    }
    

    UI Manager

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class UIManager : MonoBehaviour
    {
        public SceneFader sceneFader;
    
        public static UIManager Instance;
    
        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
            DontDestroyOnLoad(gameObject);
    
            sceneFader = GetComponentInChildren<SceneFader>();
        }
    }
    
    #16266
    Chloe Lim
    Level 9
    Moderator
    Helpful?
    Up
    1
    ::

    Hi, can I have a screen recording of how the bug happens?
    Also, ensure both scenes are added in the build,
    and also send a pic of the console if theres any errors when the bug happens

    has upvoted this post.
    #16267
    Ferral Child
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    Yep, no problem!

    View post on imgur.com

    Let me know if you need anything else!

    #16268
    Chloe Lim
    Level 9
    Moderator
    Helpful?
    Up
    1
    ::

    Ok, is your scenefader ui disabled in the hiearchy? need to enable it or there will be a null exception as the script cant find the inactive scenefader
    When your scene starts, there should be a fade out, then when moving to another scene it will fade in then out again to the new scene

    has upvoted this post.
    #16269
    Ferral Child
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    This may sound dumb, but how do I check to make sure something is enabled in the hierarchy? I tried clicking the crossed out eye with a dot and nothing is happening.

    #16271
    pepecry
    Level 6
    Participant
    Helpful?
    Up
    0
    ::

    In the inspector, If this checkbox doesn’t tick it mean it was disable
    Inspector

    #16272
    Ferral Child
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    I checked- Scene Transition, Start Point, UI Manager, Canvas, and Scene Fader are all enabled.

    #16273
    Chloe Lim
    Level 9
    Moderator
    Helpful?
    Up
    0
    ::

    Ok, in your recording it seems that your scenetransition script is failing to start the coroutine of the scene fading in the at start, which means that the UIManager is unable to find the scenefader to start the fade sequence, is the scenefader game object assigned in the inspector of your UIManager Script?

    #16274
    Ferral Child
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    It was not… I added it and I didn’t get the massive list of errors when starting up the playtest mode anymore. However, when I went into the “loading box” I got the error:

    NullReferenceException: Object reference not set to an instance of an object
    SceneTransition.OnTriggerEnter2D (UnityEngine.Collider2D _other) (at Assets/Scripts/SceneTransition.cs:32)

    #16275
    Chloe Lim
    Level 9
    Moderator
    Helpful?
    Up
    0
    ::

    When you play the scene does it start with a fade in?

    #16276
    Ferral Child
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    No.

    #16277
    Chloe Lim
    Level 9
    Moderator
    Helpful?
    Up
    1
    ::

    Ok, could you record a video of the scenefader game object inspector during play? Just play the scene and select the scenefader in the hierarchy

    has upvoted this post.
    #16280
    Ferral Child
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    Okay, I screen recorded and it captured something I didn’t notice is that the UI Manager, Canvas, and Scene Fader disappear when I play the game.

    View post on imgur.com

    Thank you for being so patient with me ;<;

    #16283
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Hi FerralChild, have you seen this post by Joseph? It may be helpful with fixing the NullReferenceExceptions that you have: https://blog.terresquall.com/community/topic/part-5-article-changes-common-issues-bugfixes/

    A lot of times, NullReferenceExceptions cause other issues because they block the rest of your function from running. Hence, whenever I have bugs, the first thing I look at are the NullReferenceExceptions.

    #16285
    Ferral Child
    Level 4
    Participant
    Helpful?
    Up
    1
    ::

    Hello, I will definitely check that out!

    I actually used another tutorial for specifically scene transitions and I was able to get it to work. Thanks y’all for being so patient with me!

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

Go to Login Page →


Advertisement below: