Forum begins after the advertisement:


[Part 7] SaveData

Viewing 12 posts - 1 through 12 (of 12 total)
  • Author
    Posts
  • #14581
    Liêm Trần
    Participant

    The save system not working when i build the game. Whenever i play the game and quit. The game load me back to first scene

    #14583
    Joseph Tang
    Moderator

    Do you mean that when you play the game, you don’t go to the Main Menu or, after starting from the Main Menu you don’t start at your first level?

    If you could show a video of how it looks that would help.

    Could you also send your SaveData.cs and PlayerController.cs?

    #14584
    Liêm Trần
    Participant

    i mean when i export to the game to desktop (the exe file). I run the game and the data wouldnot save. it does work when i play it in the editor.

    #14585
    Joseph Tang
    Moderator

    I understand your issue is in the build, however the code in the editor works the same for the build itself. Thus, I’d like to see how the issue is going on your side of things with a video, and Scripts if it’s a coding issue. There’s also a likelihood it is neither and it leads me to this:

    Without the video and scripts I can only guess the causes:
    1) Your Bench/Save point is not reliable for interaction and thus the code for interaction can be improved.
    2) You are quiting the game by the pause menu which does not have a code for saving the player’s data. Thus entering the game again brings you to your last save point [death or bench].
    3) Your PlayerController.cs is not calling SaveData.Instance.LoadPlayerData();
    4) If your health is being saved, but not the scene, your SaveData.cs does not include a code for lastScene at least for loading player data.

    #14593
    Liêm Trần
    Participant

    Oh sorry its acttualy my fault that i commented out the LoadSaveData line of code in the playerController Script. However there is a bug i just found out that i cant not hit the shade. It works fine in the editor

    #14594
    Liêm Trần
    Participant

    PlayerController

    using System.Collections;
    using System.Collections.Generic;
    // using System.Numerics;
    using System.Security.Cryptography;
    using TMPro;
    using Unity.Mathematics;
    
    // using Microsoft.Unity.VisualStudio.Editor;
    
    // using System.Numerics;
    
    using Unity.VisualScripting;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class PlayerController : MonoBehaviour
    {
    
        public Rigidbody2D rb;
    
        [Header("Horizontal Movement Settings")]
        [SerializeField] private float walkSpeed = 1f;
        [Space(5)]
    
        [Header("Vertical Movement Settings")]
        [SerializeField] private float jumptForce = 45f;
        // [SerializeField] private float jumpDistance = 5f;
        private int jumpBufferCounter = 0;
        //* How long the input buffer will be
        [SerializeField] private int jumpBufferFrames;
        //* CoyoteTime give the player a brief amount of time to jump after leaving a platform (fall off a platform, run off a legde)
        private float coyoteTimeCounter = 0;
        [SerializeField] private float coyoteTime;
        //* How many time you jump while in the air
        private int airJumpCounter = 0;
        [SerializeField] private int maxAirJumps;
        [Space(5)]
    
        [Header("Ground Check Settings")]
        [SerializeField] private Transform groundCheckPoint;
        [SerializeField] private float groundCheckY = 0.2f;
        [SerializeField] private float groundCheckX = 0.5f;
        [SerializeField] private LayerMask whatIsGround;
        [Space(5)]
    
        [Header("Dash Settings")]
        private bool canDash = true;
        private bool dashed;
        [SerializeField] private float dashSpeed;
        [SerializeField] private float dashTime;
        [SerializeField] private float dashCooldown;
        [SerializeField] GameObject dashEffect;
        [Space(5)]
    
        [Header("Attack Settings")]
        private bool attack = true;
        float timeSinceAttack;
        [SerializeField] float timeBetweenAttack;
        [SerializeField] Transform sideAttackTransform, upAttackTransform, downAttackTransform;
        [SerializeField] Vector2 SideAttackArea, UpAttackArea, DownAttackArea;
        [SerializeField] LayerMask attackableLayer;
        [SerializeField] public int damage;
        [SerializeField] GameObject slashEffect;
        [Space(5)]
    
        [Header("Recoiling Settings")]
        //* How far the player will recoil
        [SerializeField] int recoilXSteps = 5;
        [SerializeField] int recoilYSteps = 5;
        [SerializeField] float recoilXSpeed = 100;
        [SerializeField] float recoilYSpeed = 100;
        //* Stop the player from recoilling forever
        int stepsXRecoiled, stepsYRecoiled;
        [Space(5)]
    
        [Header("Health Setting")]
        public int health;
        public int maxHealth;
        public int maxTotalHealth = 8;
        public int heartShards;
        [SerializeField] GameObject bloodSpurt;
        [SerializeField] float hitFlashSpeed;
        //* Delegate used to call multiple method
        public delegate void OnHealthChangeDelegate();
        [HideInInspector] public OnHealthChangeDelegate onHealthChangeCallBack;
        float healTimer;
        [SerializeField] float timeToHeal;
        [Space(5)]
    
        [Header("Mana Settings")]
        [SerializeField] Image manaStorage;
        [SerializeField] float mana;
        [SerializeField] float manaDrainSpeed;
        [SerializeField] float manaGain;
        public bool halfMana;
    
        // public ManaOrbsHandle manaOrbsHandle;
        // public int orbShard;
        // public int manaOrbs;
        [Space(5)]
    
        [Header("Spell Settings")]
        [SerializeField] float manaSpellCost = 0.3f;
        [SerializeField] float timeBetweenCast = 0.5f;
        float timeSinceCast;
    
        //used for upspell and downspell
        [SerializeField] int spellDamage;
        [SerializeField] float downSpellForce;
        [SerializeField] GameObject sideSpellFireball;
        [SerializeField] GameObject upSpellFireball;
        [SerializeField] GameObject downSpellFireball;
        [Space(5)]
    
        [Header("Camera Settings")]
        [SerializeField] private float playerFallSpeedThreshold = -10;
        [Space(5)]
    
        [Header("Audio Settings")]
        [SerializeField] AudioClip landingSound;
        [SerializeField] AudioClip jumpSound;
        [SerializeField] AudioClip dashSound;
        [SerializeField] AudioClip attackSound;
        [SerializeField] AudioClip hurtSound;
        [SerializeField] AudioClip spellSound;
        [Space(5)]
    
        [Header("Wall Jump Settings")]
        [SerializeField] private float wallSlidingSpeed = 2f;
        [SerializeField] private Transform wallCheck;
        [SerializeField] private LayerMask wallLayer;
        [SerializeField] private float wallJumpingDuration;
        [SerializeField] private Vector2 wallJumpingPower;
        float wallJumpingDirection;
        bool isWallSliding;
        bool isWallJumping;
        [Space(5)]
    
         [Header("Unlocking Stuffs")]
        //*unlocking abilities
        public bool unlockedWallJump;
        public bool unlockedDash;
        public bool unlockedDoubleJump;
        public bool unlockedSideSpell;
        public bool unlockedUpCast;
        public bool unlockedDownCast;
    
        public bool purchasedHeartShard1;
        public bool purchasedHeartShard2;
        public bool purchasedMagicSpell;
        public bool purchasedUpgradeSword1;
        public bool purchasedUpgradeSword2;
        [Space(5)]
        
        [Header("Money")]
        public int money;
        [SerializeField] private TextMeshProUGUI moneyText;
        [Space(5)]
    
        bool restoreTime;
        float restoreTimeSpeed;
        Animator anim;
        private float gravity;
        private SpriteRenderer sr;
        private AudioSource audioSource;
    
        // Input 
        private float xAxis, yAxis;
        bool openMap;
        bool openInventory;
    
        private bool landingSoundPlayed;
    
       
    
        [HideInInspector] public PlayerStateList pState;
    
        public static PlayerController Instance;
    
        //*Destroy duplicated object that is not player
        private void Awake() {
            if (Instance != null && Instance != this) {
                Destroy(gameObject);
            } else {
                Instance = this;
            }
    
            DontDestroyOnLoad(gameObject);
        }
        void Start()
        {
            pState = GetComponent<PlayerStateList>();
            sr = GetComponent<SpriteRenderer>();
            rb = GetComponent<Rigidbody2D>();
            anim = GetComponent<Animator>();
            audioSource = GetComponent<AudioSource>();
            // manaOrbsHandle = FindObjectOfType<ManaOrbsHandle>();
    
            SaveData.Instance.LoadPlayerData();
            gravity = rb.gravityScale;
            Mana = mana;
            manaStorage.fillAmount = Mana;
            Health = maxHealth;
    
        }
    
        //* See the attack area in the scene
        private void OnDrawGizmos() {
            Gizmos.color = Color.blue;
            Gizmos.DrawWireCube(sideAttackTransform.position, SideAttackArea);
            Gizmos.DrawWireCube(upAttackTransform.position, UpAttackArea);
            Gizmos.DrawWireCube(downAttackTransform.position, DownAttackArea);
    
             Vector3 _ledgeCheckStart = transform.localScale.x > 0 ? new Vector3(groundCheckX, 0, 0) : new Vector3(-groundCheckX, 0, 0);
            Gizmos.color = Color.red;
            Gizmos.DrawRay(groundCheckPoint.transform.position + _ledgeCheckStart, Vector2.down * groundCheckY);
        }
        // private void OnDrawGizmosSelected() {
        //     Vector3 _ledgeCheckStart = transform.localScale.x > 0 ? new Vector3(groundCheckX, 0) : new Vector3(-groundCheckX, 0);
        //     Gizmos.color = Color.blue;
        //     Gizmos.DrawRay(transform.position + _ledgeCheckStart, Vector2.down * groundCheckY);
        // }
    
        void Update()
        {
            if (GameManager.Instance.gameIsPause) return;
    
            if (pState.cutscene) return;
    
            if(pState.alive) {
                GetInputs();
                ToggleMap();
                ToggleInventory();
    
            }
            UpdateJumpVariables();
            RestoreTimeScale();
    
            UpdateCameraYDampForPlayerFall();
            //* keep dashing from being interupted by other actions
            if (pState.dashing) return;
            if(pState.alive) {
                if(!isWallJumping) {
    
                    Flip();
                    Move();
                    Jump();
                }
    
                if(unlockedWallJump) {
                    WallSide();
                    WallJump();
    
                }
    
                if(unlockedDash) {
                    StartDash();
    
                }
                Attack();
                Heal();
                CastSpell();
            }
            FlashWhileInvincible();
    
            if(Input.GetKeyDown(KeyCode.L)) {
                StartCoroutine(Death());
            }
            moneyText.text = money.ToString();
    
        }
    
        private void FixedUpdate() {
            if (pState.cutscene) return;
    
            if (pState.dashing) return;
            Recoil();
    
        }
    
        private void OnTriggerEnter2D(Collider2D _other) {
            // for up and down spell cast
            if(_other.GetComponent<Enemy>() != null && pState.casting) {
                _other.GetComponent<Enemy>().EnemyHit(spellDamage, (_other.transform.position - transform.position).normalized, -recoilYSpeed);
            }
        }
    
        void ToggleMap() {
            if(openMap) {
                    UIManager.Instance.mapHandler.SetActive(true);
            } else {
    
                    UIManager.Instance.mapHandler.SetActive(false);
            }
        }
        void ToggleInventory() {
            if(openInventory) {
                    UIManager.Instance.inventory.SetActive(true);
            } else {
    
                    UIManager.Instance.inventory.SetActive(false);
            }
        }
        void GetInputs() {
            xAxis = Input.GetAxisRaw("Horizontal");
            yAxis = Input.GetAxisRaw("Vertical");
            openMap = Input.GetButton("Map");
            openInventory = Input.GetButton("Inventory");
        }
    
        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);
            //* Set walking animator to true only when the player is walking and on the ground
            anim.SetBool("Walking", rb.velocity.x != 0 && Grounded());
        }
    
        void UpdateCameraYDampForPlayerFall() {
            //if falling past a certain speed threshold
            if(rb.velocity.y < playerFallSpeedThreshold && !CamerasManager.Instance.isLerpingYDamping && !CamerasManager.Instance.hasLerpedYDamping) {
                //reset camera function
                StartCoroutine(CamerasManager.Instance.LerpYDamping(true));
            }
    
            //if standing still or moving up
            if(rb.velocity.y >= 0 && !CamerasManager.Instance.isLerpingYDamping && CamerasManager.Instance.hasLerpedYDamping) {
                //reset Camera function
                CamerasManager.Instance.hasLerpedYDamping = false;
                StartCoroutine(CamerasManager.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");
            audioSource.PlayOneShot(dashSound);
            //*Player will dash forward without falling
            rb.gravityScale = 0;
    
            int _dir = pState.lookingRight ? 1 : -1;
            rb.velocity = new Vector2(_dir * dashSpeed, 0);
    
            // if (Grounded()) Instantiate(dashEffect, transform);
            //* wait for dashtime in seconds to keep dashing in dashTime
            yield return new WaitForSeconds(dashTime);
    
            rb.gravityScale = gravity;
            pState.dashing = false;
    
            //* Wait for seconds to dash again
            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 = jumptForce * _exitDir;
            }
           
            //if exit direction is forward
            if (_exitDir.x != 0) {
                xAxis = _exitDir.x > 0 ? 1 : -1;
                Move();
            }
    
            Flip();
            yield return new WaitForSeconds(_delay);
            pState.cutscene = false;
    
        }
        void Heal() {
            //* Heal when the health is not max and the player not jumping or dashing
            if (Input.GetButton("Heal") && 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
                // manaOrbsHandle.usedMana = true;
                // manaOrbsHandle.countDown = 3f;
                Mana -= Time.deltaTime * manaDrainSpeed;
            } else {
                pState.healing = false;
                anim.SetBool("Healing", false);
    
                healTimer = 0;
    
            }
        }
        //*Check if the player is standing on the ground
    
        public float Mana {
            get { return mana; }
            set {
                // if mana statics change
                if (mana != value) {
    
                    if(!halfMana) {
    
                        mana = Mathf.Clamp(value, 0, 1);
                    } else {
                        mana = Mathf.Clamp(value, 0, 0.5f);
                        
                    }
    
                    manaStorage.fillAmount = Mana;
    
                }
            }
        }
    
        void CastSpell() {
            if (Input.GetButtonDown("CastSpell") && timeSinceCast >= timeBetweenCast && Mana >= manaSpellCost) {
                pState.casting = true;
                timeSinceCast = 0;
                StartCoroutine(CastCoroutine());
    
            } else {
                timeSinceCast += Time.deltaTime;
                // pState.casting = false;
            }
    
            if(Grounded()) {
    
                //disable downspell if on the ground
                downSpellFireball.SetActive(false);
            }
    
            //if downspell is active force player down until grounded
            if(downSpellFireball.activeInHierarchy) {
                rb.velocity += downSpellForce * Vector2.down;
            }
        }
    
        IEnumerator CastCoroutine() {
    
            audioSource.PlayOneShot(spellSound);
            //  anim.SetBool("Casting", true);
            // yield return new WaitForSeconds(0.15f);
            //Side cast
            if ((yAxis == 0 || (yAxis < 0 && Grounded())) && unlockedSideSpell ) {
                print("Side");
                anim.SetBool("Casting", true);
                yield return new WaitForSeconds(0.15f);
    
                GameObject _fireBall = Instantiate(sideSpellFireball, sideAttackTransform.position, Quaternion.identity); 
    
                //flip fireball
                if(pState.lookingRight) {
                    _fireBall.transform.eulerAngles = Vector3.zero;
                } else {
                    _fireBall.transform.eulerAngles = new Vector2(_fireBall.transform.eulerAngles.x, 180);
                    //*if not facing right, rotate the fireball 180 deg
                }
                pState.recoilingX = true;
    
                Mana -= manaSpellCost;
                // manaOrbsHandle.usedMana = true;
                // manaOrbsHandle.countDown = 3f;
                 yield return new WaitForSeconds(0.35f);
    
                   anim.SetBool("Casting", false);
            pState.casting = false;
            }
    
            //up cast
            else if( yAxis >0 && unlockedUpCast) {
                print("Up");
                 anim.SetBool("Casting", true);
                yield return new WaitForSeconds(0.15f);
    
                Instantiate(upSpellFireball, transform);
                rb.velocity = Vector2.zero;
    
                Mana -= manaSpellCost;
                //  manaOrbsHandle.usedMana = true;
                // manaOrbsHandle.countDown = 3f;
                yield return new WaitForSeconds(0.35f);
    
                  anim.SetBool("Casting", false);
            pState.casting = false;
            }
    
            //downCast
            else if(yAxis < 0 && !Grounded() && unlockedDownCast) {
                print("down");
                 anim.SetBool("Casting", true);
                yield return new WaitForSeconds(0.15f);
                downSpellFireball.SetActive(true);
    
                Mana -= manaSpellCost;
                // manaOrbsHandle.usedMana = true;
                // manaOrbsHandle.countDown = 3f;
            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 StopRecoilX() {
            stepsXRecoiled = 0;
            pState.recoilingX = false;
        }
        void StopRecoilY() {
            stepsYRecoiled = 0;
            pState.recoilingY = false;
        }
    
        public void TakeDamage(float _damage) {
            if(pState.alive) {
                audioSource.PlayOneShot(hurtSound);
                Health -= Mathf.RoundToInt(_damage);
                StartCoroutine(StopTakingDamage());
    
                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.unscaledDeltaTime * restoreTimeSpeed;
                } else {
                    Time.timeScale = 1;
                    restoreTime = false;
                }
            }
        }
    
        public void HitStopTime(float _newTimeScale, int _restoreSpeed, float _delay) {
            restoreTimeSpeed = _restoreSpeed;
            Time.timeScale = _newTimeScale;
            //* if we have been attacked
            if(_delay > 0){
                StopCoroutine(StartTimeAgain(_delay));
                StartCoroutine(StartTimeAgain(_delay));
            } else {
                restoreTime = true;
            }
    
        }
    
        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.9f);
    
            StartCoroutine(UIManager.Instance.ActivateDeathScreen());
    
            yield return new WaitForSeconds(0.9f);
            Instantiate(GameManager.Instance.shade, transform.position, quaternion.identity);
        }
    
        public void Respawned() {
            if(!pState.alive) {
                pState.alive = true;
                halfMana = true;
                UIManager.Instance.SwitchMana(UIManager.ManaState.HalfMana);
                Mana = 0; 
                Health = maxHealth;
                anim.Play("Player_Idle");
            }
        }
    
        public void RestoreMana() {
            halfMana = false;
            UIManager.Instance.SwitchMana(UIManager.ManaState.FullMana);
        }
        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);
    
                    if(onHealthChangeCallBack != null) {
                        onHealthChangeCallBack.Invoke();
                    }
                }
            }
        }
    
        void Attack() {
            timeSinceAttack += Time.deltaTime;
            if(Input.GetButtonDown("Attack") && attack && timeSinceAttack >= timeBetweenAttack) {
                timeSinceAttack = 0;
                anim.SetTrigger("Attacking");
    
                audioSource.PlayOneShot(attackSound);
    
                //* The player is not holding down or up
                if(yAxis == 0 || yAxis < 0 && Grounded()) {
    
                    int _recoilLeftOrRight = pState.lookingRight ? 1 : -1; 
                    Hit(sideAttackTransform, SideAttackArea, ref pState.recoilingX,Vector2.right * _recoilLeftOrRight, recoilXSpeed);
                    SlashEffectSide(slashEffect,0, sideAttackTransform);
                } else if(yAxis > 0) {
                    Hit(upAttackTransform, UpAttackArea, ref pState.recoilingY,Vector2.up, recoilYSpeed);
                    SlashEffectAtAngle(slashEffect, 90, upAttackTransform);
                } else if(yAxis < 0 && !Grounded()) {
                    Hit(downAttackTransform, DownAttackArea,ref pState.recoilingY,Vector2.down, recoilYSpeed);
                    SlashEffectAtAngle(slashEffect, -90, downAttackTransform);
    
                }
            }
        }
    
        private 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") || objectsToHit[i].CompareTag("GruzMother")) {
                        if(Mana < 1) {
    
                            Mana += manaGain;
                            // manaOrbsHandle.usedMana = true;
                            // manaOrbsHandle.countDown = 3f;
    
                        } else {
                            // manaOrbsHandle.UpdateMana(manaGain * 3);
                        }
                    }
                }
            }
        }
    
        void SlashEffectAtAngle(GameObject _slashEffect, int _effectAngle, Transform _attackTransform) {
            _slashEffect = Instantiate(_slashEffect, _attackTransform);
            _slashEffect.transform.eulerAngles = new Vector3(0, 0, _effectAngle);
            //*Stretch the effect to fit the area
            _slashEffect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y);
        }
        void SlashEffectSide(GameObject _slashEffect, int _effectAngle, Transform _attackTransform) {
            _slashEffect = Instantiate(_slashEffect, _attackTransform);
            _slashEffect.transform.eulerAngles = new Vector3(0, 0, _effectAngle);
            //*Stretch the effect to fit the area
            if(pState.lookingRight) {
                _slashEffect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y);
            } else {
                _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 {
            //         //*recoil left if they are facing right;
            //         rb.velocity = new Vector2(recoilXSpeed, 0);
            //     }
              
            // }
            if(pState.recoilingY) {
            // print("RecoilY is running");
    
                //*if player is pressing Down, the player is attacking downward
                rb.gravityScale = 0;
    
                if(yAxis < 0) {
                    //* gravity wont effect recoiling
                    rb.velocity = new Vector2(rb.velocity.x, recoilYSpeed);
                // } else {
                //     rb.velocity = new Vector2(rb.velocity.x, -recoilYSpeed);
                }
                airJumpCounter = 0;
    
            } else {
            // print("RecoilY is  not running");
    
                rb.gravityScale = gravity;
            }
    
            //* StopRecoiLX 
            //* if we havent recoiled full distanced yet we continue to recoil until we do
            if(pState.recoilingX && stepsXRecoiled < recoilXSteps) {
                stepsXRecoiled++;
            } else {
                StopRecoilX();
            }
            if(pState.recoilingY && stepsYRecoiled < recoilYSteps) {
                stepsYRecoiled++;
            } else {
                StopRecoilY();
            }
    
            if(Grounded() ) {
                StopRecoilY();
            }
    
        }
        void Jump() {  
    
            //! vector3
            //* The player has limited amount of frame to input the jump input before the jumpbuffer reach 0
            if(jumpBufferCounter > 0 && coyoteTimeCounter > 0 && !pState.jumping) {
                audioSource.PlayOneShot(jumpSound);
                rb.velocity = new Vector3(rb.velocity.x, jumptForce);
    
                pState.jumping = true;
            }
            //* The player will jump in the air only when press the jump button, not in the air and not exceed the maxium of airjump allowed
            if(!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump") && unlockedDoubleJump) {
                audioSource.PlayOneShot(jumpSound);
                pState.jumping = true;
                airJumpCounter++;
                rb.velocity = new Vector3(rb.velocity.x, jumptForce);
    
            }
            //* cancel the jump when release the jump button allow the player to control their jump height known as: variable jump height;     
            if(Input.GetButtonUp("Jump") && rb.velocity.y > 3) {
                pState.jumping = false;
                rb.velocity = new Vector2(rb.velocity.x, 0);
    
            }
    
            //* Creating jumping buffer: allow the player's input to be registered and stored for a brief period of time or a number of frame even if the input was executed slightly before the intened time
           
            anim.SetBool("Jumping", !Grounded());
        }
    
        void UpdateJumpVariables() {
            //* when the player is on the ground reset ...
            if (Grounded()) {
                if(!landingSoundPlayed) {
                    audioSource.PlayOneShot(landingSound);
                    landingSoundPlayed = true;
                }
                pState.jumping = false;
                coyoteTimeCounter = coyoteTime;
                airJumpCounter = 0;
            } else {
                //*Time.deltaTime is the amount of time between each frame
                coyoteTimeCounter -= Time.deltaTime;
                landingSoundPlayed = false;
            }
    
            if(Input.GetButtonDown("Jump")) {
                jumpBufferCounter = jumpBufferFrames;
            } else {
                jumpBufferCounter--;
            }
        }
        private bool Walled() {
            return Physics2D.OverlapCircle(wallCheck.position, 0.2f, wallLayer);
        }
        void WallSide() {
            Debug.Log("Wall Slide is functioning");
            if(Walled() && !Grounded() && xAxis != 0) {
                isWallSliding = true;
            Debug.Log("Wall Slide is true");
    
                rb.velocity = new Vector2(rb.velocity.x, Mathf.Clamp(rb.velocity.y, -wallSlidingSpeed, float.MaxValue));
            } else {
                isWallSliding = false;
    
            }
    
        }
    
        void WallJump() {
            Debug.Log("Wall Jump is functioning");
            if(isWallSliding) {
                isWallJumping = false;
                wallJumpingDirection = !pState.lookingRight ? 1 : -1;
    
                CancelInvoke(nameof(StopWallJumping));
            }
    
            if(Input.GetButtonDown("Jump") && isWallSliding) {
                isWallJumping = true;
                rb.velocity = new Vector2(wallJumpingDirection * wallJumpingPower.x, wallJumpingPower.y);
    
                dashed = false;
                airJumpCounter = 0;
    
                if((pState.lookingRight && transform.eulerAngles.y == 0) || (!pState.lookingRight && transform.eulerAngles.y != 0)) {
                    pState.lookingRight = !pState.lookingRight;
                    int _yRotation = pState.lookingRight ? 0 : 180;
    
                    transform.eulerAngles = new Vector2(transform.eulerAngles.x, _yRotation);
                }
    
                Invoke(nameof(StopWallJumping), wallJumpingDuration);
    
            }
        }
    
        void StopWallJumping() {
            isWallJumping = false;
        }
    }
    
    #14595
    Liêm Trần
    Participant

    save data code

    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;
    using UnityEngine.SceneManagement;
    // using UnityEditor.MPE;
    using System.Xml.Linq;
    
    [System.Serializable] 
    //* structs dont need to be present in the scene to be called
    public struct SaveData
    {
        // public Transform StartPoint;
        public static SaveData Instance;
    
        //map Relations
        public HashSet<string> sceneNames;
    
        //Save Data Relations
        public string saveSceneName;
        public Vector2 saveDataPos;
    
        public int playerMoney;
        //Player data
        public int playerHealth;
    
        public int playerDamage;
        public int playerHeartShards;
        public float playerMana;
        public int playerManaOrbs;
        public int playerManaOrbShard;
        public float playerOrb0fill, playerOrb1fill, playerOrb2fill;
        public bool playerHalfMana;
        public Vector2 playerPosition;
        public string lastScene;
    
        public bool playerUnlockedWallJump;
        public bool playerUnlockedDash;
        public bool playerUnlockedDoubleJump;
        public bool playerUnlockedSideSpell;
        public bool playerUnlockedUpSpell;
        public bool playerUnlockedDownSpell;
    
        //Enemy Data
        //Shade
        public Vector2 shadePos;
        public string sceneWithShade;
        public Quaternion shadeRot;
        public void Initialize() {
            if(!File.Exists(Application.persistentDataPath + "/save.savePoint.data")) {
                BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.savePoint.data"));
            }
            if(!File.Exists(Application.persistentDataPath + "/save.player.data")) {
                BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.player.data"));
            }
            if(!File.Exists(Application.persistentDataPath + "/save.shade.data")) {
                BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.shade.data"));
            }
            if(sceneNames == null) {
                sceneNames = new HashSet<string>();
            }
        }
    
        public void SaveSavePoint() {
            using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.savePoint.data"))) {
                writer.Write(saveSceneName);
                writer.Write(saveDataPos.x);
                writer.Write(saveDataPos.y);
    
            }
        }
    
        public void LoadSavePoint() {
            // if (File.Exists(Application.persistentDataPath + "/save.savePoint.data"))
                string savePath = Application.persistentDataPath + "/save.savePoint.data"; 
                if(File.Exists(savePath) && new FileInfo(savePath).Length > 0) 
                {
                using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.savePoint.data")))
                {
                    saveSceneName = reader.ReadString();
                    saveDataPos.x = reader.ReadSingle();
                    saveDataPos.y = reader.ReadSingle();
                }
            }
        }
    
        public void SavePlayerData() {
           using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data"))) {
                playerMoney = PlayerController.Instance.money;
                writer.Write(playerMoney);
    
                playerHealth = PlayerController.Instance.Health;
                writer.Write(playerHealth);
    
                playerDamage = PlayerController.Instance.damage;
                writer.Write(playerDamage);
    
                playerHeartShards = PlayerController.Instance.heartShards;
                writer.Write(playerHeartShards);
    
                playerMana = PlayerController.Instance.Mana;
                writer.Write(playerMana);
                playerHalfMana = PlayerController.Instance.halfMana;
                writer.Write(playerHalfMana);
                // playerManaOrbs = PlayerController.Instance.manaOrbs;
                // writer.Write(playerManaOrbs);
                // playerManaOrbShard = PlayerController.Instance.orbShard;
                // writer.Write(playerManaOrbShard);
                // playerOrb0fill = PlayerController.Instance.manaOrbsHandle.orbFills[0].fillAmount;
                // writer.Write(playerOrb0fill);
                // playerOrb1fill = PlayerController.Instance.manaOrbsHandle.orbFills[1].fillAmount;
                // writer.Write(playerOrb0fill);
                // playerOrb2fill = PlayerController.Instance.manaOrbsHandle.orbFills[2].fillAmount;
                // writer.Write(playerOrb0fill);
    
                //*unlocked abilities
                playerUnlockedWallJump = PlayerController.Instance.unlockedWallJump;
                writer.Write(playerUnlockedWallJump);
    
                playerUnlockedDash = PlayerController.Instance.unlockedDash;
                writer.Write(playerUnlockedDash);
               
                playerUnlockedDoubleJump = PlayerController.Instance.unlockedDoubleJump;
                writer.Write(playerUnlockedDoubleJump);
    
                playerUnlockedSideSpell = PlayerController.Instance.unlockedSideSpell;
                writer.Write(playerUnlockedSideSpell);
                playerUnlockedUpSpell = PlayerController.Instance.unlockedUpCast;
                writer.Write(playerUnlockedUpSpell);
                playerUnlockedDownSpell = PlayerController.Instance.unlockedDownCast;
                writer.Write(playerUnlockedDownSpell);
    
                playerPosition = PlayerController.Instance.transform.position;
                writer.Write(playerPosition.x);
                writer.Write(playerPosition.y);
    
                lastScene = SceneManager.GetActiveScene().name;
                writer.Write(lastScene);
            }
        }
    
        public void LoadPlayerData() {
            // if(File.Exists(Application.persistentDataPath + "/save.player.data"))
            string savePath = Application.persistentDataPath + "/save.player.data";
            if(File.Exists(savePath) && new FileInfo(savePath).Length > 0) 
            {
                using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data"))) {
                    playerMoney = reader.ReadInt32();
                    playerHealth = reader.ReadInt32();
                    playerDamage = reader.ReadInt32();
                    playerHeartShards = reader.ReadInt32();
                    playerMana = reader.ReadSingle();
                    playerHalfMana = reader.ReadBoolean();
                    // playerManaOrbs = reader.ReadInt32();
                    // playerManaOrbShard = reader.ReadInt32();
                    // playerOrb0fill = reader.ReadSingle();
                    // playerOrb1fill = reader.ReadSingle();
                    // playerOrb2fill = reader.ReadSingle();
    
                    playerUnlockedWallJump = reader.ReadBoolean();
                    playerUnlockedDash = reader.ReadBoolean();
                    playerUnlockedDoubleJump = reader.ReadBoolean();
    
                    playerUnlockedSideSpell = reader.ReadBoolean();
                    playerUnlockedUpSpell = reader.ReadBoolean();
                    playerUnlockedDownSpell = reader.ReadBoolean();
    
                    playerPosition.x = reader.ReadSingle();
                    playerPosition.y = reader.ReadSingle();
                    lastScene = reader.ReadString();
    
                    SceneManager.LoadScene(lastScene);
                    PlayerController.Instance.transform.position = playerPosition;
                    PlayerController.Instance.halfMana = playerHalfMana;
                    PlayerController.Instance.money = playerMoney;
                    PlayerController.Instance.Health = playerHealth;
                    PlayerController.Instance.damage = playerDamage;
                    PlayerController.Instance.heartShards = playerHeartShards;
                    PlayerController.Instance.Mana = playerMana;
                    // PlayerController.Instance.manaOrbs = playerManaOrbs;
                    // PlayerController.Instance.orbShard = playerManaOrbShard;
                    // PlayerController.Instance.manaOrbsHandle.orbFills[0].fillAmount = playerOrb0fill;
                    // PlayerController.Instance.manaOrbsHandle.orbFills[1].fillAmount = playerOrb1fill;
                    // PlayerController.Instance.manaOrbsHandle.orbFills[2].fillAmount = playerOrb2fill;
    
                    PlayerController.Instance.unlockedWallJump = playerUnlockedWallJump;
                    PlayerController.Instance.unlockedDash = playerUnlockedDash;
                    PlayerController.Instance.unlockedDoubleJump = playerUnlockedDoubleJump;
    
                    PlayerController.Instance.unlockedSideSpell = playerUnlockedSideSpell;
                    PlayerController.Instance.unlockedUpCast = playerUnlockedUpSpell;
                    PlayerController.Instance.unlockedDownCast = playerUnlockedUpSpell;
                }
            } else {
                Debug.Log("File doesnt exist");
                PlayerController.Instance.halfMana = false;
                PlayerController.Instance.money = 0;
                PlayerController.Instance.Health = PlayerController.Instance.maxHealth;
                PlayerController.Instance.damage = 2;
                PlayerController.Instance.heartShards = 0;
                PlayerController.Instance.Mana = 0.5f;
    
                PlayerController.Instance.unlockedWallJump = false;
                PlayerController.Instance.unlockedDash = false;
                PlayerController.Instance.unlockedDoubleJump = false;
    
                PlayerController.Instance.unlockedSideSpell = false;
                PlayerController.Instance.unlockedUpCast = false;
                PlayerController.Instance.unlockedDownCast = false;
            }
        }
    
        public void SaveShadeData() {
            using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.shade.data")))
            {
                sceneWithShade = SceneManager.GetActiveScene().name;
                shadePos = Shade.Instance.transform.position;
                shadeRot = Shade.Instance.transform.rotation;
    
                writer.Write(sceneWithShade);
                writer.Write(shadePos.x);
                writer.Write(shadePos.y);
                writer.Write(shadeRot.y);
                writer.Write(shadeRot.y);
                writer.Write(shadeRot.z);
                writer.Write(shadeRot.w);
    
            }
        }
    
        public void LoadShadeData() {
            // if(File.Exists(Application.persistentDataPath))
            string savePath = Application.persistentDataPath + "/save.shade.data";
            if(File.Exists(savePath) && new FileInfo(savePath).Length > 0) {
                using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.shade.data"))) {
                    sceneWithShade = reader.ReadString();
                    shadePos.x = reader.ReadSingle();
                    shadePos.y = reader.ReadSingle();
    
                    float rotationX = reader.ReadSingle();
                    float rotationY = reader.ReadSingle();
                    float rotationZ = reader.ReadSingle();
                    float rotationW = reader.ReadSingle();
                    shadeRot = new Quaternion(rotationX, rotationY, rotationZ, rotationW);
                }
            } else {
                Debug.Log("Shade doesnt exists");
            }
        }
    
        public void ResetGame()
        {
            // Delete all save files if they exist
            if (File.Exists(Application.persistentDataPath + "/save.savePoint.data"))
                File.Delete(Application.persistentDataPath + "/save.savePoint.data");
    
            if (File.Exists(Application.persistentDataPath + "/save.player.data"))
                File.Delete(Application.persistentDataPath + "/save.player.data");
    
            if (File.Exists(Application.persistentDataPath + "/save.shade.data"))
                File.Delete(Application.persistentDataPath + "/save.shade.data");
    
            using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data")))
            {
                playerMoney = 0;
                writer.Write(playerMoney);
                playerHealth = 5;
                writer.Write(playerHealth);
                playerDamage = 2;
                writer.Write(playerDamage);
                playerHeartShards = 0;
                writer.Write(playerHeartShards);
    
                playerMana = 1;
                writer.Write(playerMana);
                playerHalfMana = false;
                writer.Write(playerHalfMana);
                // playerManaOrbs = 0;
                // // writer.Write(playerManaOrbs);
                // playerOrbShard = 0;
                // writer.Write(playerOrbShard);
                // playerOrb0fill = 0;
                // writer.Write(playerOrb0fill);
                // playerOrb1fill = 0;
                // writer.Write(playerOrb1fill);
                // playerOrb2fill = 0;
                // writer.Write(playerOrb2fill);
    
                playerUnlockedWallJump = false;
                writer.Write(playerUnlockedWallJump);
                playerUnlockedDash = false;
                writer.Write(playerUnlockedDash);
                playerUnlockedDoubleJump = false;
                writer.Write(playerUnlockedDoubleJump);
    
                playerUnlockedSideSpell = false;
                writer.Write(playerUnlockedSideSpell);
                playerUnlockedUpSpell = false;
                writer.Write(playerUnlockedUpSpell);
                playerUnlockedDownSpell = false;
                writer.Write(playerUnlockedDownSpell);
    
                playerPosition = new Vector2 (-126.4f,34.5f);
                writer.Write(playerPosition.x);
                writer.Write(playerPosition.y);
    
                lastScene = "Cave_1";
                writer.Write(lastScene);
            }
    
            // Optionally reload the scene to reset the game
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
        }
    }
    
    #14596
    Liêm Trần
    Participant

    video link
    video

    #14597
    Joseph Tang
    Moderator

    Can you send a picture or video of the Shade’s inspector as well as it’s script? Likely the issue lies with the shade and not the player since the player can attack the other enemies fine.

    #14598
    Liêm Trần
    Participant

    shade code

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Shade : Enemy
    {
    
        
        [SerializeField] private float chaseDistance;
        [SerializeField] private float stunDuration;
    
        float timer;
    
        public static Shade Instance;
    
        public void Awake() {
            if(Instance != null && Instance  != this) {
                Destroy(gameObject);
            } else {
                Instance = this;
            }
            SaveData.Instance.SaveShadeData();
        }
        protected override void Start()
        {
            base.Start();
            ChanegStates(EnemyStates.Shade_Idle);
        }
    
        protected override void Update()
        {
            base.Update();
            if(!PlayerController.Instance.pState.alive) {
                ChanegStates(EnemyStates.Shade_Idle);
            }
        }
    
        // Update is called once per frame
        // void Update()
        // {
            
        // }
    
        protected override void UpdateEnenmyStates()
        {
            float _dist = Vector2.Distance(transform.position, PlayerController.Instance.transform.position);
            switch(GetCurrentEnemyStates) {
                case EnemyStates.Shade_Idle:
                    if(_dist < chaseDistance) {
                        ChanegStates(EnemyStates.Shade_Chase);
                    }
                    break;
                case EnemyStates.Shade_Chase:
                    rb.MovePosition(Vector2.MoveTowards(transform.position, PlayerController.Instance.transform.position, Time.deltaTime * speed));
    
                    FlipShade();
                    break;
                case EnemyStates.Shade_Stunned:
                    timer += Time.deltaTime;
    
                    if(timer > stunDuration) {
                        ChanegStates(EnemyStates.Shade_Idle);
                        timer = 0;
                    }
                    break;
                case EnemyStates.Shade_Death:
                    Death(Random.Range(5,10));
                    break;
            }
        }
    
        protected override void Death(float _destroyTime)
        {
            rb.gravityScale = 12;
            base.Death(_destroyTime);
        }
        public override void EnemyHit(int _damageDone, Vector2 _hitDirection, float _hitForce)
        {
            base.EnemyHit(_damageDone, _hitDirection, _hitForce);
    
            if(health > 0){
                ChanegStates(EnemyStates.Shade_Stunned);
            } else {
                ChanegStates(EnemyStates.Shade_Death);
            }
        }
    
        protected override void ChangeCurrentAnimation()
        {
            if(GetCurrentEnemyStates == EnemyStates.Shade_Idle) {
                anim.Play("Player_Idle");
            }
    
            anim.SetBool("Walking", GetCurrentEnemyStates == EnemyStates.Shade_Chase);
    
            
            // anim.SetBool("Idle", GetCurrentEnemyStates == EnemyStates.Shade_Idle);
            // anim.SetBool("Chase", GetCurrentEnemyStates == EnemyStates.Shade_Chase);
            // anim.SetBool("Stunned", GetCurrentEnemyStates == EnemyStates.Shade_Stunned);
            if(GetCurrentEnemyStates == EnemyStates.Shade_Death) {
                PlayerController.Instance.RestoreMana();
                SaveData.Instance.SavePlayerData();
                anim.SetTrigger("Death");
                Destroy(gameObject, 0.5f);
            }
        }
    
        protected override void Attack()
        {
            base.Attack();
            anim.SetTrigger("Attack");
            PlayerController.Instance.TakeDamage(damage);
        }
        void FlipShade() {
            if(PlayerController.Instance.transform.position.x < transform.position.x) {
                sr.flipX = true;
            } else {
                sr.flipX = false;
            }
        }
    }
    
    #14601
    Liêm Trần
    Participant

    Screenshot-2024-05-10-140509

    #14614
    Joseph Tang
    Moderator

    I’ve tested out your code, it seems to work fine.

    I’ve looked at your video again and I think you should test this out again in your Editor. Dying, respawning then fighting the Shade again.

    I believe the problem may lie in the fact that the spawned Shade has missing variables, aside from the fact that you should equip it with the “Enemy Hurt” Sound clip. [The console error tells you that there’s a missing audio clip, which you can see in the image you sent of the inspector].

    Check that the Shade’s prefab (and by extension the spawned shade from dying) in your prefabs folder has it’s
    1) Layer set to Attackable
    2) Tag set to Enemy
    3) Inspector values all set
    4) It’s blood effect
    5) It’s hurt Audio Clip

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

Go to Login Page →


Advertisement below: