Using Event, LazyValue to re-write HealthBar script (need feedback, thanks)

I’ve just used the LazyValue and event Sam taught and the design pattern Brain mentioned to rewrite the following HealthBar script, it’s working as expected but not sure if this is a correct way to write (as this is first time I’ve learned such thing like LazyValue and event). Would like to get some feedbacks if possible:

  1. Is it necessary for using LazyValue here because I’m not sure if there is a racing condition for child component to get the component in parent by invoking GetComponentInParent() in Awake, but didn’t experience any issue if not using LazyValue.

  2. Is my event pattern used here ok or needed any correction?

Thank you in advance if anyone could provide some feedbacks.

public class HealthBar : MonoBehaviour
    {
        [SerializeField] RectTransform imgRectTransform = null;
        LazyValue<Health> healthComponent;

        void Awake()
        {
            healthComponent = new LazyValue<Health>(() => GetComponentInParent<Health>());
        }

        void OnEnable()
        {
            healthComponent.value.onHealthUpdateEvent += UpdateImageBar;
        }

        void OnDisable()
        {
            healthComponent.value.onHealthUpdateEvent += UpdateImageBar;
        }

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

        private void UpdateImageBar()
        {
            imgRectTransform.localScale = new Vector3(healthComponent.value.GetHealthFraction(), 1, 1);
        }
    }

The event was in Health script:

    public class Health : MonoBehaviour, ISaveable
    {        
        // event:
        public event Action onHealthUpdateEvent;
        
       ...
        public void TakeDamage(GameObject instigator, float damage)
        {

            healthPoints.value = Mathf.Max(healthPoints.value - damage, 0); 
            if (healthPoints.value <= 0)
            {
                Die();
                AwardExperience(instigator);
            }

            takeDamageEvent.Invoke(damage);

            onHealthUpdateEvent();    // here invoking the onHealthUpdateEvent;
        }
      ...
}

NEW UPDATE:

I just noticed that we can just using our already defined “[SerializeField] UnityEvent takeDamageEvent;” in Health.cs script and hook the UpdateImageBar() defined in HealthBar.cs script as the following, so we can do both in one event. Just wondering which approach would be better. Thank you.
image

Either way is fine, though I’d make a couple changes to the OnEnable/OnDisable methods in HealthBar.cs.
First is OnDisable, you’re subsribing to the event again instead of unsubscribing (just change the+ to a -)
In OnEnable, it’s often a good idea to immediately update the UI in OnEnable after the subscription. This prevents the mismatch between when you subscribe and when an actual change event occurs.

As to the LazyValue in HealthBar, this is unneccessary, as the Health component will exist in the parent object.

Here’s a bit of a hybrid way of letting the HealthBar subscribe to the event, but not needing two events to accomplish the feat:

public class HealthBar : MonoBehavior
{
     [SerializeField] RectTransform imgRectTransform;
     Health healthComponent;

     void Awake()
     {
          healthComponent = GetComponentInParent<Health>();
     }

     void OnEnable()
     {
           healthComponent.takeDamageEvent.AddListener(UpdateImageBar);
           UpdateImageBar(0);
     }
     void OnDisable()
     {
           healthComponent.takeDamageEvent.RemoveListener(UpdateImageBar);
     }
     
     void UpdateImageBar(float discardedParameter)
     {
           imgRectTransform.localScale = new Vector3(healthComponent.GetHealthFraction(), 1,1);
     }
}

You need the float parameter to add the listener via OnEnable, but you don’t actually need the parameter, hence my naming it discardedParameter.
Now the HeatlhBar will react to the UnityEvent as if you’d assigned it in the inspector.

Thank you for your prompt reply, you are amazing, Brain. Thank you a lot for your great feedbacks.

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

Privacy & Terms