Health resetting between scenes

Good morning,

After we made the change to our progression system, the player’s health gets replenished through portals. I looked up and down my script and I can’t figure out why. My player Prefab Does have a dedicated unique identifier.
I honestly do not know where else to look

namespace RPG.Attributes
{
    public class Health : MonoBehaviour ,ISaveable
    {
        [SerializeField]float maxHealth;
        bool isDead= false;
        public bool IsDead{get{return isDead;}}
        void Start() 
        {
            // baseStats= GetComponent<BaseStats>();
            maxHealth= GetComponent<BaseStats>().GetStatFromBaseStats(Stats.Stats.Health);
            
        }

        public float GetHealthForDisplay()
        {
            return (maxHealth/GetComponent<BaseStats>().GetStatFromBaseStats(Stats.Stats.Health)) * 100;
        }
        

        public void TakeDamage(GameObject instigator,float damage)
        {
            maxHealth= Mathf.Max(maxHealth-damage, 0);
            // print(maxHealth);
            if(maxHealth<= 0)
            {
                TriggerDeath(instigator);
            }            
        }
        private void TriggerDeath(GameObject theOnceWhoDidTheKilling)
        {
            if(isDead) return;
            GetComponent<Animator>().SetTrigger("dying");
            GetComponent<CapsuleCollider>().enabled= false;
            GetComponent<ActionScheduler>().CancelCurrentAction();
            RewardExperience(theOnceWhoDidTheKilling);
            isDead = true;
        }

        void RewardExperience(GameObject killer)
        {
            if (killer == null) return;
            float experienceToReward = GetComponent<BaseStats>().GetStatFromBaseStats(Stats.Stats.ExperienceReward);
            PlayerExperience playerExperience= killer.GetComponent<PlayerExperience>();
            if(playerExperience == null) return;
            playerExperience.GainExperience(experienceToReward);
        }

        public object CaptureState()
        {
            return maxHealth;
        }

        public void RestoreState(object state)
        {
            maxHealth = (float) state;
            if (maxHealth <= 0)
            {
                TriggerDeath(null);
            }  
        }
    }
}

Any advice?

My apologies, somehow this post slipped past me a few weeks ago.

The problem stems from the order of operations… RestoreState() is called before Start(), and after Awake(). Ordinarily, I would suggest moving the initialization from Start() to Awake(), but this creates a different problem, as BaseStats also has not resolved the correct level for the character until after RestoreState().

As a patch solution, put the maxHealth assignment in an if statement

if(maxHealth<=-1)
{
    maxHealth= GetComponent<BaseStats>().GetStatFromBaseStats(Stats.Stats.Health);
}

Since we are getting the health from BaseStats, remove the [SerializeField] from the maxHealth declaration and initialize it
float maxHealth = -1;

This sets up a trap so that if maxHealth is restored in RestoreState(), then nothing happens, but if it’s still in it’s pristine state, then maxHealth is set to the stat for the level.

In a later lesson, we’ll introduce the LazyValue, which allows us to avoid these types of race conditions altogether.

1 Like

Good morning Brian!

Indeed the solution you propose is the one that finally fix it in the later lectures!

Thank you for following up no matter how late

Cheers!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.