111 lines
3.3 KiB
C#
111 lines
3.3 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace Player
|
|
{
|
|
[System.Serializable]
|
|
public class VitalStat
|
|
{
|
|
[System.Serializable]
|
|
public class FloatEvent : UnityEvent<float> { }
|
|
|
|
[System.Serializable]
|
|
public class ThresholdRule
|
|
{
|
|
[Range(0f, 1f)] public float normalizedThreshold = 0.5f;
|
|
public UnityEvent onEnter = new UnityEvent();
|
|
public UnityEvent onExit = new UnityEvent();
|
|
[HideInInspector] public bool isBelow;
|
|
}
|
|
|
|
public string id;
|
|
public float minValue = 0f;
|
|
public float maxValue = 100f;
|
|
public float currentValue = 100f;
|
|
[FormerlySerializedAs("decayPerSecond")] public float decayPerMinute = 0f;
|
|
|
|
public FloatEvent onValueChanged = new FloatEvent();
|
|
public FloatEvent onNormalizedChanged = new FloatEvent();
|
|
|
|
public List<ThresholdRule> thresholds = new List<ThresholdRule>();
|
|
|
|
public float Normalized
|
|
{
|
|
get
|
|
{
|
|
if (Mathf.Approximately(minValue, maxValue)) return 0f;
|
|
return Mathf.InverseLerp(minValue, maxValue, currentValue);
|
|
}
|
|
}
|
|
|
|
public void Initialize(bool invokeEvents = true)
|
|
{
|
|
currentValue = Mathf.Clamp(currentValue, minValue, maxValue);
|
|
UpdateThresholdStates(invokeEvents: false);
|
|
if (invokeEvents) InvokeAll();
|
|
}
|
|
|
|
public void Tick(float deltaTime)
|
|
{
|
|
if (decayPerMinute == 0f) return;
|
|
Add(-(decayPerMinute / 60f) * deltaTime);
|
|
}
|
|
|
|
public void Add(float delta)
|
|
{
|
|
SetCurrent(currentValue + delta);
|
|
}
|
|
|
|
public void SetCurrent(float value)
|
|
{
|
|
float clamped = Mathf.Clamp(value, minValue, maxValue);
|
|
if (Mathf.Approximately(clamped, currentValue)) return;
|
|
currentValue = clamped;
|
|
InvokeAll();
|
|
UpdateThresholdStates(invokeEvents: true);
|
|
}
|
|
|
|
public void SetRange(float min, float max, bool preserveNormalized = true)
|
|
{
|
|
float normalized = Normalized;
|
|
minValue = min;
|
|
maxValue = max;
|
|
if (preserveNormalized)
|
|
{
|
|
currentValue = Mathf.Lerp(minValue, maxValue, normalized);
|
|
}
|
|
else
|
|
{
|
|
currentValue = Mathf.Clamp(currentValue, minValue, maxValue);
|
|
}
|
|
|
|
InvokeAll();
|
|
UpdateThresholdStates(invokeEvents: true);
|
|
}
|
|
|
|
void InvokeAll()
|
|
{
|
|
onValueChanged.Invoke(currentValue);
|
|
onNormalizedChanged.Invoke(Normalized);
|
|
}
|
|
|
|
void UpdateThresholdStates(bool invokeEvents)
|
|
{
|
|
float normalized = Normalized;
|
|
for (int i = 0; i < thresholds.Count; i++)
|
|
{
|
|
ThresholdRule rule = thresholds[i];
|
|
bool below = normalized <= rule.normalizedThreshold;
|
|
if (invokeEvents)
|
|
{
|
|
if (!rule.isBelow && below) rule.onEnter.Invoke();
|
|
else if (rule.isBelow && !below) rule.onExit.Invoke();
|
|
}
|
|
rule.isBelow = below;
|
|
}
|
|
}
|
|
}
|
|
}
|