You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
14 KiB
C#
355 lines
14 KiB
C#
2 months ago
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||
|
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.UI;
|
||
|
using System.Collections;
|
||
|
|
||
|
namespace Lofelt.NiceVibrations
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Add this bar to an object and link it to a bar (possibly the same object the script is on), and you'll be able to resize the bar object based on a current value, located between a min and max value.
|
||
|
/// See the HealthBar.cs script for a use case
|
||
|
/// </summary>
|
||
|
public class MMProgressBar : MonoBehaviour
|
||
|
{
|
||
|
/// the possible fill modes
|
||
|
public enum FillModes { LocalScale, FillAmount, Width, Height }
|
||
|
/// the possible directions for the fill (for local scale and fill amount only)
|
||
|
public enum BarDirections { LeftToRight, RightToLeft, UpToDown, DownToUp }
|
||
|
/// the possible timescales the bar can work on
|
||
|
public enum TimeScales { UnscaledTime, Time }
|
||
|
|
||
|
[Header("General Settings")]
|
||
|
/// the local scale or fillamount value to reach when the bar is empty
|
||
|
public float StartValue = 0f;
|
||
|
/// the local scale or fillamount value to reach when the bar is full
|
||
|
public float EndValue = 1f;
|
||
|
/// the direction this bar moves to
|
||
|
public BarDirections BarDirection = BarDirections.LeftToRight;
|
||
|
/// the foreground bar's fill mode
|
||
|
public FillModes FillMode = FillModes.LocalScale;
|
||
|
/// defines whether the bar will work on scaled or unscaled time (whether or not it'll keep moving if time is slowed down for example)
|
||
|
public TimeScales TimeScale = TimeScales.UnscaledTime;
|
||
|
|
||
|
[Header("Foreground Bar Settings")]
|
||
|
/// whether or not the foreground bar should lerp
|
||
|
public bool LerpForegroundBar = true;
|
||
|
/// the speed at which to lerp the foreground bar
|
||
|
public float LerpForegroundBarSpeed = 15f;
|
||
|
|
||
|
[Header("Delayed Bar Settings")]
|
||
|
/// the delay before the delayed bar moves (in seconds)
|
||
|
public float Delay = 1f;
|
||
|
/// whether or not the delayed bar's animation should lerp
|
||
|
public bool LerpDelayedBar = true;
|
||
|
/// the speed at which to lerp the delayed bar
|
||
|
public float LerpDelayedBarSpeed = 15f;
|
||
|
|
||
|
[Header("Bindings")]
|
||
|
/// optional - the ID of the player associated to this bar
|
||
|
public string PlayerID;
|
||
|
/// the delayed bar
|
||
|
public Transform DelayedBar;
|
||
|
/// the main, foreground bar
|
||
|
public Transform ForegroundBar;
|
||
|
|
||
|
[Header("Bump")]
|
||
|
/// whether or not the bar should "bump" when changing value
|
||
|
public bool BumpScaleOnChange = true;
|
||
|
/// whether or not the bar should bump when its value increases
|
||
|
public bool BumpOnIncrease = false;
|
||
|
/// the duration of the bump animation
|
||
|
public float BumpDuration = 0.2f;
|
||
|
/// whether or not the bar should flash when bumping
|
||
|
public bool ChangeColorWhenBumping = true;
|
||
|
/// the color to apply to the bar when bumping
|
||
|
public Color BumpColor = Color.white;
|
||
|
/// the curve to map the bump animation on
|
||
|
public AnimationCurve BumpAnimationCurve = new AnimationCurve(new Keyframe(1, 1), new Keyframe(0.3f, 1.05f), new Keyframe(1, 1));
|
||
|
/// the curve to map the bump animation color animation on
|
||
|
public AnimationCurve BumpColorAnimationCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.3f, 1f), new Keyframe(1, 0));
|
||
|
/// whether or not the bar is bumping right now
|
||
|
public bool Bumping { get; protected set; }
|
||
|
|
||
|
[Header("Realtime")]
|
||
|
/// whether or not this progress bar should update itself every update (if not, you'll have to update it using the UpdateBar method
|
||
|
public bool AutoUpdating = false;
|
||
|
/// the current progress of the bar
|
||
|
[Range(0f, 1f)]
|
||
|
public float BarProgress;
|
||
|
|
||
|
protected float _targetFill;
|
||
|
protected Vector3 _targetLocalScale = Vector3.one;
|
||
|
protected float _newPercent;
|
||
|
protected float _lastPercent;
|
||
|
protected float _lastUpdateTimestamp;
|
||
|
protected bool _bump = false;
|
||
|
protected Color _initialColor;
|
||
|
protected Vector3 _initialScale;
|
||
|
protected Vector3 _newScale;
|
||
|
protected Image _foregroundImage;
|
||
|
protected Image _delayedImage;
|
||
|
protected bool _initialized;
|
||
|
protected Vector2 _initialFrontBarSize;
|
||
|
|
||
|
/// <summary>
|
||
|
/// On start we store our image component
|
||
|
/// </summary>
|
||
|
protected virtual void Start()
|
||
|
{
|
||
|
_initialScale = this.transform.localScale;
|
||
|
|
||
|
if (ForegroundBar != null)
|
||
|
{
|
||
|
_foregroundImage = ForegroundBar.GetComponent<Image>();
|
||
|
_initialFrontBarSize = _foregroundImage.rectTransform.sizeDelta;
|
||
|
}
|
||
|
if (DelayedBar != null)
|
||
|
{
|
||
|
_delayedImage = DelayedBar.GetComponent<Image>();
|
||
|
}
|
||
|
_initialized = true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// On Update we update our bars
|
||
|
/// </summary>
|
||
|
protected virtual void Update()
|
||
|
{
|
||
|
AutoUpdate();
|
||
|
UpdateFrontBar();
|
||
|
UpdateDelayedBar();
|
||
|
}
|
||
|
|
||
|
protected virtual void AutoUpdate()
|
||
|
{
|
||
|
if (!AutoUpdating)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_newPercent = Remap(BarProgress, 0f, 1f, StartValue, EndValue);
|
||
|
_targetFill = _newPercent;
|
||
|
_lastUpdateTimestamp = (TimeScale == TimeScales.Time) ? Time.time : Time.unscaledTime;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the front bar's scale
|
||
|
/// </summary>
|
||
|
protected virtual void UpdateFrontBar()
|
||
|
{
|
||
|
float currentDeltaTime = (TimeScale == TimeScales.Time) ? Time.deltaTime : Time.unscaledTime;
|
||
|
|
||
|
if (ForegroundBar != null)
|
||
|
{
|
||
|
switch (FillMode)
|
||
|
{
|
||
|
case FillModes.LocalScale:
|
||
|
_targetLocalScale = Vector3.one;
|
||
|
switch (BarDirection)
|
||
|
{
|
||
|
case BarDirections.LeftToRight:
|
||
|
_targetLocalScale.x = _targetFill;
|
||
|
break;
|
||
|
case BarDirections.RightToLeft:
|
||
|
_targetLocalScale.x = 1f - _targetFill;
|
||
|
break;
|
||
|
case BarDirections.DownToUp:
|
||
|
_targetLocalScale.y = _targetFill;
|
||
|
break;
|
||
|
case BarDirections.UpToDown:
|
||
|
_targetLocalScale.y = 1f - _targetFill;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (LerpForegroundBar)
|
||
|
{
|
||
|
_newScale = Vector3.Lerp(ForegroundBar.localScale, _targetLocalScale, currentDeltaTime * LerpForegroundBarSpeed);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_newScale = _targetLocalScale;
|
||
|
}
|
||
|
|
||
|
ForegroundBar.localScale = _newScale;
|
||
|
break;
|
||
|
|
||
|
case FillModes.Width:
|
||
|
if (_foregroundImage == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
float newSizeX = Remap(_targetFill, 0f, 1f, 0, _initialFrontBarSize.x);
|
||
|
newSizeX = Mathf.Lerp(_foregroundImage.rectTransform.sizeDelta.x, newSizeX, currentDeltaTime * LerpForegroundBarSpeed);
|
||
|
_foregroundImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, newSizeX);
|
||
|
break;
|
||
|
|
||
|
case FillModes.Height:
|
||
|
if (_foregroundImage == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
float newSizeY = Remap(_targetFill, 0f, 1f, 0, _initialFrontBarSize.y);
|
||
|
newSizeY = Mathf.Lerp(_foregroundImage.rectTransform.sizeDelta.x, newSizeY, currentDeltaTime * LerpForegroundBarSpeed);
|
||
|
_foregroundImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, newSizeY);
|
||
|
break;
|
||
|
|
||
|
case FillModes.FillAmount:
|
||
|
if (_foregroundImage == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
if (LerpForegroundBar)
|
||
|
{
|
||
|
_foregroundImage.fillAmount = Mathf.Lerp(_foregroundImage.fillAmount, _targetFill, currentDeltaTime * LerpForegroundBarSpeed);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_foregroundImage.fillAmount = _targetFill;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the delayed bar's scale
|
||
|
/// </summary>
|
||
|
protected virtual void UpdateDelayedBar()
|
||
|
{
|
||
|
float currentDeltaTime = (TimeScale == TimeScales.Time) ? Time.deltaTime : Time.unscaledDeltaTime;
|
||
|
float currentTime = (TimeScale == TimeScales.Time) ? Time.time : Time.unscaledTime;
|
||
|
|
||
|
if (DelayedBar != null)
|
||
|
{
|
||
|
if (currentTime - _lastUpdateTimestamp > Delay)
|
||
|
{
|
||
|
if (FillMode == FillModes.LocalScale)
|
||
|
{
|
||
|
_targetLocalScale = Vector3.one;
|
||
|
|
||
|
switch (BarDirection)
|
||
|
{
|
||
|
case BarDirections.LeftToRight:
|
||
|
_targetLocalScale.x = _targetFill;
|
||
|
break;
|
||
|
case BarDirections.RightToLeft:
|
||
|
_targetLocalScale.x = 1f - _targetFill;
|
||
|
break;
|
||
|
case BarDirections.DownToUp:
|
||
|
_targetLocalScale.y = _targetFill;
|
||
|
break;
|
||
|
case BarDirections.UpToDown:
|
||
|
_targetLocalScale.y = 1f - _targetFill;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (LerpDelayedBar)
|
||
|
{
|
||
|
_newScale = Vector3.Lerp(DelayedBar.localScale, _targetLocalScale, currentDeltaTime * LerpDelayedBarSpeed);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_newScale = _targetLocalScale;
|
||
|
}
|
||
|
DelayedBar.localScale = _newScale;
|
||
|
}
|
||
|
|
||
|
if ((FillMode == FillModes.FillAmount) && (_delayedImage != null))
|
||
|
{
|
||
|
if (LerpDelayedBar)
|
||
|
{
|
||
|
_delayedImage.fillAmount = Mathf.Lerp(_delayedImage.fillAmount, _targetFill, currentDeltaTime * LerpDelayedBarSpeed);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_delayedImage.fillAmount = _targetFill;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the bar's values based on the specified parameters
|
||
|
/// </summary>
|
||
|
/// <param name="currentValue">Current value.</param>
|
||
|
/// <param name="minValue">Minimum value.</param>
|
||
|
/// <param name="maxValue">Max value.</param>
|
||
|
public virtual void UpdateBar(float currentValue, float minValue, float maxValue)
|
||
|
{
|
||
|
_newPercent = Remap(currentValue, minValue, maxValue, StartValue, EndValue);
|
||
|
if ((_newPercent != BarProgress) && !Bumping)
|
||
|
{
|
||
|
Bump();
|
||
|
}
|
||
|
BarProgress = _newPercent;
|
||
|
_targetFill = _newPercent;
|
||
|
_lastUpdateTimestamp = (TimeScale == TimeScales.Time) ? Time.time : Time.unscaledTime;
|
||
|
_lastPercent = _newPercent;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Triggers a camera bump
|
||
|
/// </summary>
|
||
|
public virtual void Bump()
|
||
|
{
|
||
|
if (!BumpScaleOnChange || !_initialized)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
if (!BumpOnIncrease && (_lastPercent < _newPercent))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
if (this.gameObject.activeInHierarchy)
|
||
|
{
|
||
|
StartCoroutine(BumpCoroutine());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// A coroutine that (usually quickly) changes the scale of the bar
|
||
|
/// </summary>
|
||
|
/// <returns>The coroutine.</returns>
|
||
|
protected virtual IEnumerator BumpCoroutine()
|
||
|
{
|
||
|
float journey = 0f;
|
||
|
float currentDeltaTime = (TimeScale == TimeScales.Time) ? Time.deltaTime : Time.unscaledDeltaTime;
|
||
|
|
||
|
Bumping = true;
|
||
|
if (_foregroundImage != null)
|
||
|
{
|
||
|
_initialColor = _foregroundImage.color;
|
||
|
}
|
||
|
|
||
|
while (journey <= BumpDuration)
|
||
|
{
|
||
|
journey = journey + currentDeltaTime;
|
||
|
float percent = Mathf.Clamp01(journey / BumpDuration);
|
||
|
float curvePercent = BumpAnimationCurve.Evaluate(percent);
|
||
|
float colorCurvePercent = BumpColorAnimationCurve.Evaluate(percent);
|
||
|
this.transform.localScale = curvePercent * _initialScale;
|
||
|
|
||
|
if (ChangeColorWhenBumping && (_foregroundImage != null))
|
||
|
{
|
||
|
_foregroundImage.color = Color.Lerp(_initialColor, BumpColor, colorCurvePercent);
|
||
|
}
|
||
|
|
||
|
yield return null;
|
||
|
}
|
||
|
_foregroundImage.color = _initialColor;
|
||
|
Bumping = false;
|
||
|
yield return null;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
protected virtual float Remap(float x, float A, float B, float C, float D)
|
||
|
{
|
||
|
float remappedValue = C + (x - A) / (B - A) * (D - C);
|
||
|
return remappedValue;
|
||
|
}
|
||
|
}
|
||
|
}
|