Help with Health Bar HUD

I implemented the Health bar concept from the RPG Core Combat Creator course into a Health bar HUD, and I did the same for Mana and Experience. It was all working so I saved the project and closed Unity, then I opened and it was still working. I added some icons (Inventory, Quests, and Pause) to the HUD, also I changed the name of the UI prefab. Because, I designed 5 other HUDs (on google drive) so I could playtest them to get feedback on which HUD the player testers liked. It was still working, and I saved the project and closed Unity. I opened Unity to do some more work, and that is when things got buggy.
First the trail of the arrows are colliding off of the arrow, but that is not my main concern. My main concern is the Health bar HUD isn’t working, the health display is working fine but not the bar. Also, the health bar from the enemies is working. Here is the code and a screenshot of the console.

using UnityEngine;
using RPG.Saving;
using RPG.Stats;
using RPG.Core;
using System;
using RPG.Utils;
using UnityEngine.Events;

namespace RPG.Attributes
{
    public class Health : MonoBehaviour, ISaveable
    {
        [SerializeField] float regenerationPercentage = 70;
        [SerializeField] TakeDamageEvent takeDamage;
        public UnityEvent onDie;

        [System.Serializable]
        public class TakeDamageEvent : UnityEvent<float>
        {

        }

        LazyValue <float> healthPoints;

        bool wasDeadLastFrame = false;

        void Awake()
        {
            healthPoints = new LazyValue<float>(GetInitialHealth);
        }

        private float GetInitialHealth()
        {
            return GetComponent<BaseStats>().GetStat(Stat.Health);
        }

        void Start()
        {
            healthPoints.ForceInit();
        }

        void OnEnable()
        {
            GetComponent<BaseStats>().onLevelUp += RegenerateHealth;
        }
       
        void OnDisable()
        {
            GetComponent<BaseStats>().onLevelUp -= RegenerateHealth;
        }

        public bool IsDead()
        {
            return healthPoints.value <=0;
        }
        
        public void TakeDamage(GameObject instigator, float damage)
        {
            healthPoints.value = Mathf.Max(healthPoints.value - damage, 0);

            if(IsDead())
            {
                onDie.Invoke();
                AwardExperience(instigator);
            }
            else
            {
                takeDamage.Invoke(damage);
            }
            UpdateState();
        }

        public void Heal(float healthToRestore)
        {
            healthPoints.value = Mathf.Min(healthPoints.value + healthToRestore, GetMaxHealthPoints());
            UpdateState();
        }

        public float GetHealthPoints()
        {
            return healthPoints.value;
        }

        public float GetMaxHealthPoints()
        {
            return GetComponent<BaseStats>().GetStat(Stat.Health);
        }
     
        public float GetPercentage() //To Display the health percentage in text.  Subject to change.
        {
            return 100 * GetFraction();
        }

        public float GetFraction()
        {
            return healthPoints.value / GetComponent<BaseStats>().GetStat(Stat.Health);
        }

        private void UpdateState()
        {
            Animator animator = GetComponent<Animator>();
            if (!wasDeadLastFrame && IsDead())
            {
                GetComponent<Animator>().SetTrigger("Die");
                GetComponent<ActionScheduler>().CancelCurrentAction();
            }

            if(wasDeadLastFrame && !IsDead())
            {
                animator.Rebind();
            }
           
            wasDeadLastFrame = IsDead();
        }

        private void AwardExperience(GameObject instigator)
        {
            Experience experience = instigator.GetComponent<Experience>();
            if (experience == null) return;

            experience.GainExperience(GetComponent<BaseStats>().GetStat(Stat.ExperienceReward));
        }

        private void RegenerateHealth()
        {
            float regenHealthPoints = GetComponent<BaseStats>().GetStat(Stat.Health) * (regenerationPercentage / 100);
            healthPoints.value = Mathf.Max(healthPoints.value, regenHealthPoints);
        }

        public object CaptureState()
        {
            return healthPoints.value;
        }

        public void RestoreState(object state)
        {
            healthPoints.value = (float)state;
            UpdateState();           
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace RPG.Attributes
{
    public class HealthBarHUD : MonoBehaviour
    {
        [SerializeField] Health healthComponent = null;
        [SerializeField] RectTransform foreground = null;

        void Update()
        {
            foreground.localScale = new Vector3(healthComponent.GetFraction(), 1, 1);
        }
    }
}

Thank you,
Eric

1 Like

The error in question is in Health.cs, in GetFraction()

        public float GetFraction()
        {
            return healthPoints.value / GetComponent<BaseStats>().GetStat(Stat.Health);
        }

There are two things that could be null on this line: The healthPoints lazyValue (though it is set in Awake(), so unlikely) or the GetComponent<BaseStats>().
It’s unlikely that the BaseStats is not on your Player, or you wouldn’t have gotten this far…

I see that you’ve linked the Player in Prefab mode on the HealthBarUI… .it’s impossible to link the Player in the Scene, but you could link the Player Prefab… the problem is that the Player Prefab is never instantiated, and isn’t really the Player in the scene… The Player should only be linked to the UI within the Scene, not in Prefab mode, then linked to the Player in the scene and not the prefab.

1 Like

Yes, I needed to link the player to the UI Health Component variable within the scene. The health bar decreases but I have it reduced to check the foreground and it is not filling up. Is there a way to link it up without doing this way, so I could avoid this? I was thinking GetComponent() function in the HealthBarHUD script.

Thank you,
Eric

Yes, but you need to find the Player…

void Awake()
{
    healthComponent = GameObject.FindWithTag("Player").GetComponent<Health>();
}
1 Like

Privacy & Terms