Forum begins after the advertisement:


[Part 7] My Respawn button isnt working

Home Forums Video Game Tutorial Series Creating a Metroidvania in Unity [Part 7] My Respawn button isnt working

Viewing 20 posts - 1 through 20 (of 22 total)
  • Author
    Posts
  • #13611
    Anuk Thotawatta
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    when playercharacter dies and when i press the respawn button nothing happens(the button doesn’t even look like its clicking). And the button has been set to interactable.

    My “bench” code:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Coffin : MonoBehaviour
    {
        public bool interacted;
        // Start is called before the first frame update
        void Start()
        {
    
        }
    
        // Update is called once per frame
        void Update()
        {
    
        }
        private void OnTriggerStay2D(Collider2D _collision) {
            if(_collision.CompareTag("Player") && Input.GetButtonDown("Interact")){
                interacted = true;
            }
        }
    }

    my UIManager code:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Coffin : MonoBehaviour
    {
        public bool interacted;
        // Start is called before the first frame update
        void Start()
        {
    
        }
    
        // Update is called once per frame
        void Update()
        {
    
        }
        private void OnTriggerStay2D(Collider2D _collision) {
            if(_collision.CompareTag("Player") && Input.GetButtonDown("Interact")){
                interacted = true;
            }
        }
    }

    My gamemanager code:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class GameManager : MonoBehaviour
    {
        public string transitionedFromScene;
        public Vector2 platformingRespawnPoint;
        public Vector2 respawnPoint;
        [SerializeField] Coffin coffin;
    
        public static GameManager Instance { get; private set; }
        private void Awake()
        {
            if(Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
            DontDestroyOnLoad(gameObject);
            coffin = FindObjectOfType<Coffin>();
        }
    
        public void RespawnPlayer(){
            Debug.Log("Respawned");
            if(coffin != null){
                if(coffin.interacted){
                    respawnPoint = coffin.transform.position;
                }
                else{
                    respawnPoint = platformingRespawnPoint;
                }
            }
            else{
                respawnPoint = platformingRespawnPoint;
            }
    
            PlayerController.Instance.transform.position = respawnPoint;
    
            StartCoroutine(UIManager.Instance.DeactivateDeathScreen());
            PlayerController.Instance.Respawned();
        }
    }
    #13612
    Anuk Thotawatta
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    Update: put a event system on the canvas with stand alone input module and now, when i click button the game pauses and gives me the error “Coroutine couldn’t be started because the the game object ‘Game Manager’ is inactive!”

    #13614
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::

    Hi Anuk, for the respawn button, have a read of this post and see if it helps fix your issue. It is related to the save issue with benches noted in this topic: https://blog.terresquall.com/community/topic/part-7-scenefader-nullreferenceexception-and-savedata-endofstreamexception/

    Update: put a event system on the canvas with stand alone input module and now, when i click button the game pauses and gives me the error “Coroutine couldn’t be started because the the game object ‘Game Manager’ is inactive!”

    For this issue, you will need to check your Hierarchy and see if the Game Manager object is inactive. If it is, what in your code is turning it inactive when the game is running?

    #13630
    Anuk Thotawatta
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    ok, now respawning kind of works for the rooms that dont have a bench. which means i respawn at the start point of the scene i died instead of the bench on a separate scene.

    also after respawning, why are my heartfills invisible? only after i get hit once my heart containers become visible again.

    #13633
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::
    also after respawning, why are my heartfills invisible? only after i get hit once my heart containers become visible again.

    Check your heartContainers to see if you assigned the parent GameObject to one of the items.

    #13643
    Anuk Thotawatta
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    i went further into the save system video and now my character respawns at the bench if he dies in another scene, but doesnt respawn(respawn button unresponsive) if he dies in the scene where the bench is.

    another problem is that my cave_1 map is visible after starting the game as intended but after i interact with a bench in cave_4, instead of updating the scenes i came across, the map becomes invisible

    here’s the code for bench/coffin:

    <code>using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class Coffin : MonoBehaviour
    {
        public bool interacted;
        // Start is called before the first frame update
        void Start()
        {
    
        }
    
        // Update is called once per frame
        void Update()
        {
    
        }
        private void OnTriggerStay2D(Collider2D _collision) {
            if(_collision.CompareTag("Player") && Input.GetButtonDown("Interact")){
                interacted = true;
                SaveData.Instance.coffinSceneName = SceneManager.GetActiveScene().name;
                SaveData.Instance.coffinpos = new Vector2(gameObject.transform.position.x,gameObject.transform.position.y);
                SaveData.Instance.SaveCoffin();
            }
        }
        private void OnTriggerExit2D(Collider2D _collision) {
            if(_collision.CompareTag("Player")){
                interacted = false;
            }
        }
    }</code>

    Map Manager cade:

    <code>using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class MapManager : MonoBehaviour
    {
        // Start is called before the first frame update
    
        [SerializeField] GameObject[] maps;
        Coffin coffin;
    
        private void OnEnable() {
            coffin = FindObjectOfType<Coffin>();
            if(coffin != null){
                if(coffin.interacted){
                    UpdateMap();
                }
            }
        }
    
        void UpdateMap(){
            var savedScenes = SaveData.Instance.sceneNames;
            for(int i=0;i<maps.Length;i++){
                if(savedScenes.Contains("Cave_"+i+1)){
                    maps[i].SetActive(true);
                }
                else{
                    maps[i].SetActive(false);
                }
            }
        }
    }
    </code>
    #13646
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::
    i went further into the save system video and now my character respawns at the bench if he dies in another scene, but doesnt respawn(respawn button unresponsive) if he dies in the scene where the bench is.
    When you mouse over the button, does it get highlighted?
    another problem is that my cave_1 map is visible after starting the game as intended but after i interact with a bench in cave_4, instead of updating the scenes i came across, the map becomes invisible
    When the map becomes invisible, do they still exist in the Hierarchy?
    #13650
    Anuk Thotawatta
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    no, if i die in the room with the bench the respawn button doesn’t get highlighted

    When the map becomes invisible, they exist in the Hierarchy. but they are turned off

    #13651
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::
    no, if i die in the room with the bench the respawn button doesn’t get highlighted
    The respawn button may be blocked by another element in your scene. Can you try moving the button up so it becomes the first element under its parent?
    When the map becomes invisible, they exist in the Hierarchy. but they are turned off
    For this, can you check whether the scenes you have for the maps match the names of the GameObjects in your Map Manager component?
    #13654
    Anuk Thotawatta
    Level 4
    Participant
    Helpful?
    Up
    0
    ::
    View post on imgur.com

    the names of the scenes are correct and are in correct order

    #13655
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::
    the names of the scenes are correct and are in correct order
    Move the Death Screen above the Scene Fader and see if it fixes the Respawn button not responding.
    #13669
    Anuk Thotawatta
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    I tried and that doesn’t seem to be the problem. when I move death screen above scene fader and play the scene fader sits on top of the death screen and I cant click the button. the respawn button works if I die in another scene. I cant interact with it only if I die in the scene with the bench in it.

    #13670
    Anuk Thotawatta
    Level 4
    Participant
    #13674
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::

    Can you show me your Hierarchy when the Respawn doesn’t work? Record something like the above.

    #13694
    Anuk Thotawatta
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    The Hierarchy’s dont look any different when i die in each scene.

    also in the video my heartfills are invisible after reaspawn. how do i fix that

    #13707
    Joseph Tang
    Level 13
    Moderator
    Helpful?
    Up
    0
    ::

    Sorry for a late response on your issue. Unless something else is happening in the “Death Screen” from the Scene’s hierarchy, which we can’t see from the Imgur video as it previews the Prefab’s hierarchy.

    I believe the issue lies in the fact that your Image is above your Button in the “Death Screen” hierarchy as seen in this image.

    View post on imgur.com
    The Image is below the Button, meaning it’s placed above the Button in the scene.

    You can test this out by changing the Y position of the Image over your button and see if it’s graphic is covering the Button. If it is, then this can be fixed by simply swapping them in the hierarchy.

    Example:

    Image is behind the Buttons
    Image is in front of the Buttons

    [Though, this is just an attempt at a solution as I find it perplexing that the button worked the first attempt but didn’t in the second.]

    #13708
    Anuk Thotawatta
    Level 4
    Participant
    Helpful?
    Up
    0
    ::

    THANK YOU so much. it was the death image that had a bit of empty space that was covering the button. It works perfectly now. Thank you for your support.

    #14531
    Alex
    Level 10
    Former Patron
    Helpful?
    Up
    0
    ::

    Hey, were you able to fix the problem? I’m also having a similar issue where, in Cave 1, like in the video, everything works. When I die in another scene, for example, cave 2, the death screen shows up, but I can no longer click the respawn button or spawn back in.

    Edit: Tried everything in page 2 and still doesn’t work

    #14532
    Joseph Tang
    Level 13
    Moderator
    Helpful?
    Up
    0
    ::

    Hi Alex, does your Cave_2 scene contain an EventSystem? Take a look at this short to see if it helps:

    I would recommend sending a video of how your respawn may not be working. Sometimes you may be able to interact with the button, but the method is not firing correctly, then perhaps a referenced game object become missing, multiple instances of your singleton are found, your scene is not added to your build editor.

    #14533
    Alex
    Level 10
    Former Patron
    Helpful?
    Up
    0
    ::

    I was, in fact, missing the EventSystem in my other scenes; adding it allowed me to be able to click the respawn button, but it still did not spawn me back in. This only occurs in cave 2 and Cave 3. Cave 1 is working perfectly fine.

    Demo

    View post on imgur.com

    playerController.cs

    <code>using System.Collections;
    using System.Collections.Generic;
    using Unity.VisualScripting;
    using UnityEngine;
    using UnityEngine.UI;
    
    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;
        private float gravity;
        [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;
        private bool canDash = true;
        private bool dashed;
        [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;
    
        bool restoreTime;
        float restoreTimeSpeed;
        [Space(5)]
    
        [Header("Recoil Settings")]
        [SerializeField] int recoilXSteps = 5;
        [SerializeField] int recoilYSteps = 5;
        [SerializeField] float recoilXSpeed = 100;
        [SerializeField] float recoilYSpeed = 100;
        private 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;
        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 Settings")]
        // Spell Stats
        [SerializeField] float manaSpellCost = 0.3f;
        [SerializeField] float timeBetweenCast = 0.5f;
        [SerializeField] float spellDamage; // Up Spell Explosion and Down Spell Fireball
        [SerializeField] float downSpellForce; // Dive Spell
    
        // Spell Cast Objects
        [SerializeField] GameObject sideSpellFireball;
        [SerializeField] GameObject upSpellExplosion;
        [SerializeField] GameObject downSpellFireball;
        float timeSinceCast;
        float castOrHealtimer;
        [Space(5)]
    
        [HideInInspector] public PlayerStateList pState;
        [HideInInspector] public Rigidbody2D rb;
        Animator anim;
        private SpriteRenderer sr;
        private float xAxis, yAxis;
        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;
            if (Health == 0) {
                pState.alive = false;
                GameManager.Instance.RespawnPlayer();
            }
            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;
            if (pState.alive) {
                GetInputs();
            }
            UpdateJumpVariables();
            RestoreTimeScale();
    
            if (pState.dashing) return;
            FlashWhileInvincible();
            if (pState.alive) {
                Move();
                Heal();
                CastSpell();
                Flip();
                Jump();
                StartDash();
                Attack();
            }
            if (pState.healing) return;
        }
    
        private void OnTriggerEnter2D(Collider2D _other) // For up and down cast spell
        {
            if (_other.GetComponent<Enemy>() != null && pState.casting)
            {
                _other.GetComponent<Enemy>().EnemyHit(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.GetButton("Cast/Heal"))
            {
                castOrHealtimer += Time.deltaTime;
            }
        }
    
        void Flip()
        {
            if (xAxis < 0)
            {
                // transform.localScale = new Vector2(-1, transform.localScale.y);
                transform.eulerAngles = new Vector2(0, 180);
                pState.lookingRight = false;
            }
            else if (xAxis > 0)
            {
                // transform.localScale = new Vector2(1, transform.localScale.y);
                transform.eulerAngles = new Vector2(0, 0);
                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;
            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 is upwards
            if (_exitDir.y > 0)
            {
                rb.velocity = jumpForce * _exitDir;
            }
    
            // IF exit direction required horizontal movement
            if (_exitDir.x != 0)
            {
                xAxis = _exitDir.x > 0 ? 1 : -1;
                Move();
            }
            yield return new WaitForSeconds(_delay);
            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);
                    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>().EnemyHit(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)
        {
            if(pState.alive) {
                Health -= Mathf.RoundToInt(_damage);
                if(Health <= 0) {
                    Health = 0;
                    StartCoroutine(Death());
                } else {
                    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);
        }
    
        IEnumerator Death() {
            pState.alive = false;
            Time.timeScale = 1f;
            GameObject _bloodSpurtParticles = Instantiate(bloodSpurt, transform.position, Quaternion.identity);
            Destroy(_bloodSpurtParticles, 1.5f);
            anim.SetTrigger("Death");
            yield return new WaitForSeconds(0.8f); 
            StartCoroutine(UIManager.Instance.ActivateDeathScreen());
        }
    
        public void Respawned()
        {
            if(!pState.alive)
            {
                rb.constraints = RigidbodyConstraints2D.None;
                rb.constraints = RigidbodyConstraints2D.FreezeRotation;
                GetComponent<BoxCollider2D>().enabled = true;
                pState.alive = true;
                Health = maxHealth;
                anim.Play("player_Idle");
            }
        }
    
        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") && castOrHealtimer > 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 != value)
                {
                    mana = Mathf.Clamp(value, 0, 1);
                    manaStorage.fillAmount = Mana;
                }
            }
        }
    
        void CastSpell()
        {
            if (Input.GetButtonUp("Cast/Heal") && castOrHealtimer <= 0.15f && timeSinceCast >= timeBetweenCast && Mana >= manaSpellCost)
            {
                pState.casting = true;
                timeSinceCast = 0;
                StartCoroutine(CastCoroutine());
            }
            else
            {
                timeSinceCast += Time.deltaTime;
            }
    
            if (!Input.GetButton("Cast/Heal"))
            {
                castOrHealtimer = 0;
            }
    
            if (Grounded())
            {
                // Disable down spell 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.15f);
    
            // Side Spell 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 deg
                }
                pState.recoilingX = true;
            }
            // Up Spell Cast
            else if (yAxis > 0)
            {
                Instantiate(upSpellExplosion, transform);
                rb.velocity = Vector2.zero;
            }
    
            // Down  Spell 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 (jumpBufferCounter > 0 && coyoteTimeCounter > 0 && !pState.jumping)
            {
                rb.velocity = new Vector3(rb.velocity.x, jumpForce);
                pState.jumping = true;
            }
    
            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--;
            }
        }
    }
    </code>

    GameManager.cs

    <code>using System.Collections;
    using System.Collections.Generic;
    using Unity.VisualScripting;
    using UnityEngine;
    
    public class GameManager : MonoBehaviour
    {
        public string transitionedFromScene;
        public Vector2 platformRespawnPoint;
        public Vector2 respawnPoint;
        [SerializeField] Bench bench;
    
        public static GameManager Instance { get; private set; }
    
        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
            DontDestroyOnLoad(gameObject);
            bench = FindAnyObjectByType<Bench>();
        }
    
        public void RespawnPlayer()
        {
            if(bench.interacted) {
                respawnPoint = bench.transform.position;
            } else {
                respawnPoint = platformRespawnPoint;
            }
            playerController.Instance.transform.position = respawnPoint;
            StartCoroutine(UIManager.Instance.DeactivateDeathScreen());
            playerController.Instance.Respawned();
        }
    }
    </code>

    UIManager.cs

    <code>using System.Collections;
    using System.Collections.Generic;
    using Unity.VisualScripting;
    using UnityEditor.SearchService;
    using UnityEngine;
    
    public class UIManager : MonoBehaviour
    {
        public SceneFader sceneFader;
        public static UIManager Instance; 
        [SerializeField] GameObject deathScreen;
    
        private void Awake() {
            if(Instance != null && Instance != this) {
                Destroy(gameObject);
            }
            else {
                Instance = this;
            }
            DontDestroyOnLoad(gameObject);
            sceneFader = GetComponentInChildren<SceneFader>();
        }
    
        public IEnumerator ActivateDeathScreen() {
            yield return new WaitForSeconds(0.8f);
            StartCoroutine(sceneFader.Fade(SceneFader.FadeDirection.In));
    
            yield return new WaitForSeconds(0.9f);
            deathScreen.SetActive(true);
        }
    
        public IEnumerator DeactivateDeathScreen() {
            yield return new WaitForSeconds(0.5f);
            deathScreen.SetActive(false);
            StartCoroutine(sceneFader.Fade(SceneFader.FadeDirection.Out));
        }
    }
    </code>
Viewing 20 posts - 1 through 20 (of 22 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: