Health Interactable

In my current game, Crypt Hunter, I have two types of health pickups. small that the player just picks up and large where the player interacts in order to get the health. Here is the interactable I created for the large health. I use them to give the player a percentage of their current health so the pickups will level up with the player. You could easily change this to a flat amount or adjust other attributes like Mana or Shield or whatever. I copped quite a bit of this from Justin's code and tried to follow his conventions just for consistencies. I send a message when the item is interacted to trigger the removal of the item which I animate in another behavior.

I didn't make a fancy inspector, sorry!

using UnityEngine;
using UnityEngine.Events;
using Opsive.UltimateCharacterController.Traits;
using Opsive.UltimateCharacterController.Utility;
using Opsive.UltimateCharacterController.Audio;
using Opsive.UltimateCharacterController.Events;

public class HealthInteractable : MonoBehaviour, IInteractableTarget, IInteractableMessage
    [Tooltip("Health provided as a percentage.")]
    [Range(0.0f, 1.0f)]
    [SerializeField] protected float m_health = 1;
    [Tooltip("The UI message that should be displayed.")]
    [SerializeField] protected string m_BoolEnabledMessage;
    [Tooltip("An array of audio clips that can be played when the interaction starts.")]
    [SerializeField] protected AudioClip[] m_InteractAudioClips;
    [Tooltip("Unity event invoked when the interaction occurs.")]
    [SerializeField] protected UnityEvent m_OnUseEvent;

    public float Health { get { return m_health; } set { m_health = value; } }
    public string EnanabledMessage { get { return m_BoolEnabledMessage; } set { m_BoolEnabledMessage = value; } }
    public AudioClip[] InteractAudioClips { get { return m_InteractAudioClips; } set { m_InteractAudioClips = value; } }
    public UnityEvent OnUseEvent { get { return m_OnUseEvent; } set { m_OnUseEvent = value; } }

    private GameObject m_GameObject;
    private bool m_HasInteracted;
    private int m_AudioClipIndex = -1;

    private void Awake()
        m_GameObject = gameObject;

    /// <summary>
    /// Can the target be interacted with?
    /// </summary>
    /// <param name="character">The character that wants to interactact with the target.</param>
    /// <returns>True if the target can be interacted with.</returns>
    public bool CanInteract(GameObject character)
        return !m_HasInteracted;

    /// <summary>
    /// Interact with the target.
    /// </summary>
    /// <param name="character">The character that wants to interactact with the target.</param>
    public void Interact(GameObject character)
        var health = character.GetCachedParentComponent<Health>();
        var attributeManager = character.GetCachedParentComponent<AttributeManager>();
        if (health != null && attributeManager != null && health.IsAlive())
            var healthName = health.HealthAttributeName;
            var maxHealth = attributeManager.GetAttribute(healthName).MaxValue;
            health.Heal(Mathf.FloorToInt(maxHealth * m_health));

        if (m_InteractAudioClips.Length > 0)
            // Sequentually switch between audio clips.
            m_AudioClipIndex = (m_AudioClipIndex + 1) % m_InteractAudioClips.Length;
            AudioManager.Play(m_GameObject, m_InteractAudioClips[m_AudioClipIndex]);

        m_HasInteracted = true;

        EventHandler.ExecuteEvent(m_GameObject, "OnHealthInteraction");
        if (m_OnUseEvent != null)

    public string AbilityMessage()
        return m_BoolEnabledMessage;