using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using MoreMountains.Tools; #if MM_TEXTMESHPRO using TMPro; #endif using UnityEngine.Events; using UnityEngine.Serialization; namespace MoreMountains.Tools { /// /// 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 /// [MMRequiresConstantRepaint] [AddComponentMenu("More Mountains/Tools/GUI/MMProgressBar")] public class MMProgressBar : MMMonoBehaviour { public enum MMProgressBarStates {Idle, Decreasing, Increasing, InDecreasingDelay, InIncreasingDelay } /// the possible fill modes public enum FillModes { LocalScale, FillAmount, Width, Height, Anchor } /// 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 } /// the possible ways to animate the bar fill public enum BarFillModes { SpeedBased, FixedDuration } [MMInspectorGroup("Bindings", true, 10)] /// optional - the ID of the player associated to this bar [Tooltip("optional - the ID of the player associated to this bar")] public string PlayerID; /// the main, foreground bar [Tooltip("the main, foreground bar")] public Transform ForegroundBar; /// the delayed bar that will show when moving from a value to a new, lower value [Tooltip("the delayed bar that will show when moving from a value to a new, lower value")] [FormerlySerializedAs("DelayedBar")] public Transform DelayedBarDecreasing; /// the delayed bar that will show when moving from a value to a new, higher value [Tooltip("the delayed bar that will show when moving from a value to a new, higher value")] public Transform DelayedBarIncreasing; [MMInspectorGroup("Fill Settings", true, 11)] /// the local scale or fillamount value to reach when the value associated to the bar is at 0% [FormerlySerializedAs("StartValue")] [Range(0f,1f)] [Tooltip("the local scale or fillamount value to reach when the value associated to the bar is at 0%")] public float MinimumBarFillValue = 0f; /// the local scale or fillamount value to reach when the bar is full [FormerlySerializedAs("EndValue")] [Range(0f,1f)] [Tooltip("the local scale or fillamount value to reach when the bar is full")] public float MaximumBarFillValue = 1f; /// whether or not to initialize the value of the bar on start [Tooltip("whether or not to initialize the value of the bar on start")] public bool SetInitialFillValueOnStart = false; /// the initial value of the bar [MMCondition("SetInitialFillValueOnStart", true)] [Range(0f,1f)] [Tooltip("the initial value of the bar")] public float InitialFillValue = 0f; /// the direction this bar moves to [Tooltip("the direction this bar moves to")] public BarDirections BarDirection = BarDirections.LeftToRight; /// the foreground bar's fill mode [Tooltip("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) [Tooltip("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; /// the selected fill animation mode [Tooltip("the selected fill animation mode")] public BarFillModes BarFillMode = BarFillModes.SpeedBased; [MMInspectorGroup("Foreground Bar Settings", true, 12)] /// whether or not the foreground bar should lerp [Tooltip("whether or not the foreground bar should lerp")] public bool LerpForegroundBar = true; /// the speed at which to lerp the foreground bar [Tooltip("the speed at which to lerp the foreground bar")] [MMCondition("LerpForegroundBar", true)] public float LerpForegroundBarSpeedDecreasing = 15f; /// the speed at which to lerp the foreground bar if value is increasing [Tooltip("the speed at which to lerp the foreground bar if value is increasing")] [FormerlySerializedAs("LerpForegroundBarSpeed")] [MMCondition("LerpForegroundBar", true)] public float LerpForegroundBarSpeedIncreasing = 15f; /// the speed at which to lerp the foreground bar if speed is decreasing [Tooltip("the speed at which to lerp the foreground bar if speed is decreasing")] [MMCondition("LerpForegroundBar", true)] public float LerpForegroundBarDurationDecreasing = 0.2f; /// the duration each update of the foreground bar should take (only if in fixed duration bar fill mode) [Tooltip("the duration each update of the foreground bar should take (only if in fixed duration bar fill mode)")] [MMCondition("LerpForegroundBar", true)] public float LerpForegroundBarDurationIncreasing = 0.2f; /// the curve to use when animating the foreground bar fill decreasing [Tooltip("the curve to use when animating the foreground bar fill decreasing")] [MMCondition("LerpForegroundBar", true)] public AnimationCurve LerpForegroundBarCurveDecreasing = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); /// the curve to use when animating the foreground bar fill increasing [Tooltip("the curve to use when animating the foreground bar fill increasing")] [MMCondition("LerpForegroundBar", true)] public AnimationCurve LerpForegroundBarCurveIncreasing = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); [MMInspectorGroup("Delayed Bar Decreasing", true, 13)] /// the delay before the delayed bar moves (in seconds) [Tooltip("the delay before the delayed bar moves (in seconds)")] [FormerlySerializedAs("Delay")] public float DecreasingDelay = 1f; /// whether or not the delayed bar's animation should lerp [Tooltip("whether or not the delayed bar's animation should lerp")] [FormerlySerializedAs("LerpDelayedBar")] public bool LerpDecreasingDelayedBar = true; /// the speed at which to lerp the delayed bar [Tooltip("the speed at which to lerp the delayed bar")] [FormerlySerializedAs("LerpDelayedBarSpeed")] [MMCondition("LerpDecreasingDelayedBar", true)] public float LerpDecreasingDelayedBarSpeed = 15f; /// the duration each update of the foreground bar should take (only if in fixed duration bar fill mode) [Tooltip("the duration each update of the foreground bar should take (only if in fixed duration bar fill mode)")] [FormerlySerializedAs("LerpDelayedBarDuration")] [MMCondition("LerpDecreasingDelayedBar", true)] public float LerpDecreasingDelayedBarDuration = 0.2f; /// the curve to use when animating the delayed bar fill [Tooltip("the curve to use when animating the delayed bar fill")] [FormerlySerializedAs("LerpDelayedBarCurve")] [MMCondition("LerpDecreasingDelayedBar", true)] public AnimationCurve LerpDecreasingDelayedBarCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); [MMInspectorGroup("Delayed Bar Increasing", true, 18)] /// the delay before the delayed bar moves (in seconds) [Tooltip("the delay before the delayed bar moves (in seconds)")] public float IncreasingDelay = 1f; /// whether or not the delayed bar's animation should lerp [Tooltip("whether or not the delayed bar's animation should lerp")] public bool LerpIncreasingDelayedBar = true; /// the speed at which to lerp the delayed bar [Tooltip("the speed at which to lerp the delayed bar")] [MMCondition("LerpIncreasingDelayedBar", true)] public float LerpIncreasingDelayedBarSpeed = 15f; /// the duration each update of the foreground bar should take (only if in fixed duration bar fill mode) [Tooltip("the duration each update of the foreground bar should take (only if in fixed duration bar fill mode)")] [MMCondition("LerpIncreasingDelayedBar", true)] public float LerpIncreasingDelayedBarDuration = 0.2f; /// the curve to use when animating the delayed bar fill [Tooltip("the curve to use when animating the delayed bar fill")] [MMCondition("LerpIncreasingDelayedBar", true)] public AnimationCurve LerpIncreasingDelayedBarCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); [MMInspectorGroup("Bump", true, 14)] /// whether or not the bar should "bump" when changing value [Tooltip("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 [Tooltip("whether or not the bar should bump when its value increases")] public bool BumpOnIncrease = false; /// whether or not the bar should bump when its value decreases [Tooltip("whether or not the bar should bump when its value decreases")] public bool BumpOnDecrease = false; /// the duration of the bump animation [Tooltip("the duration of the bump animation")] public float BumpDuration = 0.2f; /// whether or not the bar should flash when bumping [Tooltip("whether or not the bar should flash when bumping")] public bool ChangeColorWhenBumping = true; /// whether or not to store the initial bar color before a bump [Tooltip("whether or not to store the initial bar color before a bump")] public bool StoreBarColorOnPlay = true; /// the color to apply to the bar when bumping [Tooltip("the color to apply to the bar when bumping")] [MMCondition("ChangeColorWhenBumping", true)] public Color BumpColor = Color.white; /// the curve to map the bump animation on [Tooltip("the curve to map the bump animation on")] [FormerlySerializedAs("BumpAnimationCurve")] public AnimationCurve BumpScaleAnimationCurve = 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 [Tooltip("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; } [MMInspectorGroup("Events", true, 16)] /// an event to trigger every time the bar bumps [Tooltip("an event to trigger every time the bar bumps")] public UnityEvent OnBump; /// an event to trigger every time the bar starts decreasing [Tooltip("an event to trigger every time the bar starts decreasing")] public UnityEvent OnBarMovementDecreasingStart; /// an event to trigger every time the bar stops decreasing [Tooltip("an event to trigger every time the bar stops decreasing")] public UnityEvent OnBarMovementDecreasingStop; /// an event to trigger every time the bar starts increasing [Tooltip("an event to trigger every time the bar starts increasing")] public UnityEvent OnBarMovementIncreasingStart; /// an event to trigger every time the bar stops increasing [Tooltip("an event to trigger every time the bar stops increasing")] public UnityEvent OnBarMovementIncreasingStop; [MMInspectorGroup("Text", true, 20)] /// a Text object to update with the bar's value [Tooltip("a Text object to update with the bar's value")] public Text PercentageText; #if MM_TEXTMESHPRO /// a TMPro text object to update with the bar's value [Tooltip("a TMPro text object to update with the bar's value")] public TMP_Text PercentageTextMeshPro; #endif /// a prefix to always add to the bar's value display [Tooltip("a prefix to always add to the bar's value display")] public string TextPrefix; /// a suffix to always add to the bar's value display [Tooltip("a suffix to always add to the bar's value display")] public string TextSuffix; /// a value multiplier to always apply to the bar's value when displaying it [Tooltip("a value multiplier to always apply to the bar's value when displaying it")] public float TextValueMultiplier = 1f; /// the format in which the text should display [Tooltip("the format in which the text should display")] public string TextFormat = "{000}"; /// whether or not to display the total after the current value [Tooltip("whether or not to display the total after the current value")] public bool DisplayTotal = false; /// if DisplayTotal is true, the separator to put between the current value and the total [Tooltip("if DisplayTotal is true, the separator to put between the current value and the total")] [MMCondition("DisplayTotal", true)] public string TotalSeparator = " / "; [MMInspectorGroup("Debug", true, 15)] /// the value the bar will move to if you press the DebugSet button [Tooltip("the value the bar will move to if you press the DebugSet button")] [Range(0f, 1f)] public float DebugNewTargetValue; [MMInspectorButton("DebugUpdateBar")] public bool DebugUpdateBarButton; [MMInspectorButton("DebugSetBar")] public bool DebugSetBarButton; [MMInspectorButton("Bump")] public bool TestBumpButton; [MMInspectorButton("Plus10Percent")] public bool Plus10PercentButton; [MMInspectorButton("Minus10Percent")] public bool Minus10PercentButton; [MMInspectorGroup("Debug Read Only", true, 19)] /// the current progress of the bar, ideally read only [Tooltip("the current progress of the bar, ideally read only")] [Range(0f,1f)] public float BarProgress; /// the current progress of the bar, ideally read only [Tooltip("the current progress of the bar, ideally read only")] [Range(0f,1f)] public float BarTarget; /// the current progress of the delayed bar increasing [Tooltip("the current progress of the delayed bar increasing")] [Range(0f,1f)] public float DelayedBarIncreasingProgress; /// the current progress of the delayed bar decreasing [Tooltip("the current progress of the delayed bar decreasing")] [Range(0f,1f)] public float DelayedBarDecreasingProgress; protected bool _initialized; protected Vector2 _initialBarSize; protected Color _initialColor; protected Vector3 _initialScale; protected Image _foregroundImage; protected Image _delayedDecreasingImage; protected Image _delayedIncreasingImage; protected Vector3 _targetLocalScale = Vector3.one; protected float _newPercent; protected float _percentLastTimeBarWasUpdated; protected float _lastUpdateTimestamp; protected float _time; protected float _deltaTime; protected int _direction; protected Coroutine _coroutine; protected bool _coroutineShouldRun = false; protected bool _isDelayedBarIncreasingNotNull; protected bool _isDelayedBarDecreasingNotNull; protected bool _actualUpdate; protected Vector2 _anchorVector; protected float _delayedBarDecreasingProgress; protected float _delayedBarIncreasingProgress; protected MMProgressBarStates CurrentState = MMProgressBarStates.Idle; protected string _updatedText; protected string _totalText; protected bool _isForegroundBarNotNull; protected bool _isForegroundImageNotNull; protected bool _isPercentageTextNotNull; protected bool _isPercentageTextMeshProNotNull; #region PUBLIC_API /// /// Updates the bar's values, using a normalized value /// /// public virtual void UpdateBar01(float normalizedValue) { UpdateBar(Mathf.Clamp01(normalizedValue), 0f, 1f); } /// /// Updates the bar's values based on the specified parameters /// /// Current value. /// Minimum value. /// Max value. public virtual void UpdateBar(float currentValue,float minValue,float maxValue) { if (!_initialized) { Initialization(); } if (StoreBarColorOnPlay) { StoreInitialColor(); } if (!this.gameObject.activeInHierarchy) { this.gameObject.SetActive(true); } _newPercent = MMMaths.Remap(currentValue, minValue, maxValue, MinimumBarFillValue, MaximumBarFillValue); _actualUpdate = (BarTarget != _newPercent); if (!_actualUpdate) { return; } if (CurrentState != MMProgressBarStates.Idle) { if ((CurrentState == MMProgressBarStates.Decreasing) || (CurrentState == MMProgressBarStates.InDecreasingDelay)) { if (_newPercent >= BarTarget) { StopCoroutine(_coroutine); SetBar01(BarTarget); } } if ((CurrentState == MMProgressBarStates.Increasing) || (CurrentState == MMProgressBarStates.InIncreasingDelay)) { if (_newPercent <= BarTarget) { StopCoroutine(_coroutine); SetBar01(BarTarget); } } } _percentLastTimeBarWasUpdated = BarProgress; _delayedBarDecreasingProgress = DelayedBarDecreasingProgress; _delayedBarIncreasingProgress = DelayedBarIncreasingProgress; BarTarget = _newPercent; if ((_newPercent != _percentLastTimeBarWasUpdated) && !Bumping) { Bump(); } DetermineDeltaTime(); _lastUpdateTimestamp = _time; DetermineDirection(); if (_direction < 0) { OnBarMovementDecreasingStart?.Invoke(); } else { OnBarMovementIncreasingStart?.Invoke(); } if (_coroutine != null) { StopCoroutine(_coroutine); } _coroutineShouldRun = true; if (this.gameObject.activeInHierarchy) { _coroutine = StartCoroutine(UpdateBarsCo()); } else { SetBar(currentValue, minValue, maxValue); } UpdateText(); } /// /// Sets the bar value to the one specified /// /// /// /// public virtual void SetBar(float currentValue, float minValue, float maxValue) { float newPercent = MMMaths.Remap(currentValue, minValue, maxValue, 0f, 1f); SetBar01(newPercent); } /// /// Sets the bar value to the normalized value set in parameter /// /// public virtual void SetBar01(float newPercent) { if (!_initialized) { Initialization(); } newPercent = MMMaths.Remap(newPercent, 0f, 1f, MinimumBarFillValue, MaximumBarFillValue); BarProgress = newPercent; DelayedBarDecreasingProgress = newPercent; DelayedBarIncreasingProgress = newPercent; //_newPercent = newPercent; BarTarget = newPercent; _percentLastTimeBarWasUpdated = newPercent; _delayedBarDecreasingProgress = DelayedBarDecreasingProgress; _delayedBarIncreasingProgress = DelayedBarIncreasingProgress; SetBarInternal(newPercent, ForegroundBar, _foregroundImage, _initialBarSize); SetBarInternal(newPercent, DelayedBarDecreasing, _delayedDecreasingImage, _initialBarSize); SetBarInternal(newPercent, DelayedBarIncreasing, _delayedIncreasingImage, _initialBarSize); UpdateText(); _coroutineShouldRun = false; CurrentState = MMProgressBarStates.Idle; } #endregion PUBLIC_API #region START /// /// On start we store our image component /// protected virtual void Start() { Initialization(); } protected virtual void OnEnable() { if (!_initialized) { return; } StoreInitialColor(); } public virtual void Initialization() { _isForegroundBarNotNull = ForegroundBar != null; _isDelayedBarDecreasingNotNull = DelayedBarDecreasing != null; _isDelayedBarIncreasingNotNull = DelayedBarIncreasing != null; _isPercentageTextNotNull = PercentageText != null; #if MM_TEXTMESHPRO _isPercentageTextMeshProNotNull = PercentageTextMeshPro != null; #endif _initialScale = this.transform.localScale; if (_isForegroundBarNotNull) { _foregroundImage = ForegroundBar.GetComponent(); _isForegroundImageNotNull = _foregroundImage != null; _initialBarSize = _foregroundImage.rectTransform.sizeDelta; } if (_isDelayedBarDecreasingNotNull) { _delayedDecreasingImage = DelayedBarDecreasing.GetComponent(); } if (_isDelayedBarIncreasingNotNull) { _delayedIncreasingImage = DelayedBarIncreasing.GetComponent(); } _initialized = true; StoreInitialColor(); _percentLastTimeBarWasUpdated = BarProgress; if (SetInitialFillValueOnStart) { SetBar01(InitialFillValue); } } protected virtual void StoreInitialColor() { if (!Bumping && _isForegroundImageNotNull) { _initialColor = _foregroundImage.color; } } #endregion START #region TESTS /// /// This test method, called via the inspector button of the same name, lets you test what happens when you update the bar to a certain value /// protected virtual void DebugUpdateBar() { this.UpdateBar01(DebugNewTargetValue); } /// /// Test method /// protected virtual void DebugSetBar() { this.SetBar01(DebugNewTargetValue); } /// /// Test method /// public virtual void Plus10Percent() { float newProgress = BarTarget + 0.1f; newProgress = Mathf.Clamp(newProgress, 0f, 1f); UpdateBar01(newProgress); } /// /// Test method /// public virtual void Minus10Percent() { float newProgress = BarTarget - 0.1f; newProgress = Mathf.Clamp(newProgress, 0f, 1f); UpdateBar01(newProgress); } #endregion TESTS protected virtual void UpdateText() { _updatedText = TextPrefix + (BarTarget * TextValueMultiplier).ToString(TextFormat); if (DisplayTotal) { _updatedText += TotalSeparator + (TextValueMultiplier).ToString(TextFormat); } _updatedText += TextSuffix; if (_isPercentageTextNotNull) { PercentageText.text = _updatedText; } #if MM_TEXTMESHPRO if (_isPercentageTextMeshProNotNull) { PercentageTextMeshPro.text = _updatedText; } #endif } /// /// On Update we update our bars /// protected virtual IEnumerator UpdateBarsCo() { while (_coroutineShouldRun) { DetermineDeltaTime(); DetermineDirection(); UpdateBars(); yield return null; } CurrentState = MMProgressBarStates.Idle; yield break; } protected virtual void DetermineDeltaTime() { _deltaTime = (TimeScale == TimeScales.Time) ? Time.deltaTime : Time.unscaledDeltaTime; _time = (TimeScale == TimeScales.Time) ? Time.time : Time.unscaledTime; } protected virtual void DetermineDirection() { _direction = (_newPercent > _percentLastTimeBarWasUpdated) ? 1 : -1; } /// /// Updates the foreground bar's scale /// protected virtual void UpdateBars() { float newFill; float newFillDelayed; float t1, t2 = 0f; // if the value is decreasing if (_direction < 0) { newFill = ComputeNewFill(LerpForegroundBar, LerpForegroundBarSpeedDecreasing, LerpForegroundBarDurationDecreasing, LerpForegroundBarCurveDecreasing, 0f, _percentLastTimeBarWasUpdated, out t1); SetBarInternal(newFill, ForegroundBar, _foregroundImage, _initialBarSize); SetBarInternal(newFill, DelayedBarIncreasing, _delayedIncreasingImage, _initialBarSize); BarProgress = newFill; DelayedBarIncreasingProgress = newFill; CurrentState = MMProgressBarStates.Decreasing; if (_time - _lastUpdateTimestamp > DecreasingDelay) { newFillDelayed = ComputeNewFill(LerpDecreasingDelayedBar, LerpDecreasingDelayedBarSpeed, LerpDecreasingDelayedBarDuration, LerpDecreasingDelayedBarCurve, DecreasingDelay,_delayedBarDecreasingProgress, out t2); SetBarInternal(newFillDelayed, DelayedBarDecreasing, _delayedDecreasingImage, _initialBarSize); DelayedBarDecreasingProgress = newFillDelayed; CurrentState = MMProgressBarStates.InDecreasingDelay; } } else // if the value is increasing { newFill = ComputeNewFill(LerpForegroundBar, LerpForegroundBarSpeedIncreasing, LerpForegroundBarDurationIncreasing, LerpForegroundBarCurveIncreasing, 0f, _delayedBarIncreasingProgress, out t1); SetBarInternal(newFill, DelayedBarIncreasing, _delayedIncreasingImage, _initialBarSize); DelayedBarIncreasingProgress = newFill; CurrentState = MMProgressBarStates.Increasing; if (DelayedBarIncreasing == null) { newFill = ComputeNewFill(LerpForegroundBar, LerpForegroundBarSpeedIncreasing, LerpForegroundBarDurationIncreasing, LerpForegroundBarCurveIncreasing, 0f, _percentLastTimeBarWasUpdated, out t2); SetBarInternal(newFill, DelayedBarDecreasing, _delayedDecreasingImage, _initialBarSize); SetBarInternal(newFill, ForegroundBar, _foregroundImage, _initialBarSize); BarProgress = newFill; DelayedBarDecreasingProgress = newFill; CurrentState = MMProgressBarStates.InDecreasingDelay; } else { if (_time - _lastUpdateTimestamp > IncreasingDelay) { newFillDelayed = ComputeNewFill(LerpIncreasingDelayedBar, LerpForegroundBarSpeedIncreasing, LerpForegroundBarDurationIncreasing, LerpForegroundBarCurveIncreasing, IncreasingDelay, _delayedBarDecreasingProgress, out t2); SetBarInternal(newFillDelayed, DelayedBarDecreasing, _delayedDecreasingImage, _initialBarSize); SetBarInternal(newFillDelayed, ForegroundBar, _foregroundImage, _initialBarSize); BarProgress = newFillDelayed; DelayedBarDecreasingProgress = newFillDelayed; CurrentState = MMProgressBarStates.InDecreasingDelay; } } } if ((t1 >= 1f) && (t2 >= 1f)) { _coroutineShouldRun = false; if (_direction > 0) { OnBarMovementIncreasingStop?.Invoke(); } else { OnBarMovementDecreasingStop?.Invoke(); } } } protected virtual float ComputeNewFill(bool lerpBar, float barSpeed, float barDuration, AnimationCurve barCurve, float delay, float lastPercent, out float t) { float newFill = 0f; t = 0f; if (lerpBar) { float delta = 0f; float timeSpent = _time - _lastUpdateTimestamp - delay; float speed = barSpeed; if (speed == 0f) { speed = 1f; } float duration = (BarFillMode == BarFillModes.FixedDuration) ? barDuration : (Mathf.Abs(_newPercent - lastPercent)) / speed; delta = MMMaths.Remap(timeSpent, 0f, duration, 0f, 1f); delta = Mathf.Clamp(delta, 0f, 1f); t = delta; if (t < 1f) { delta = barCurve.Evaluate(delta); newFill = Mathf.LerpUnclamped(lastPercent, _newPercent, delta); } else { newFill = _newPercent; } } else { newFill = _newPercent; } newFill = Mathf.Clamp( newFill, 0f, 1f); return newFill; } protected virtual void SetBarInternal(float newAmount, Transform bar, Image image, Vector2 initialSize) { if (bar == null) { return; } switch (FillMode) { case FillModes.LocalScale: _targetLocalScale = Vector3.one; switch (BarDirection) { case BarDirections.LeftToRight: _targetLocalScale.x = newAmount; break; case BarDirections.RightToLeft: _targetLocalScale.x = 1f - newAmount; break; case BarDirections.DownToUp: _targetLocalScale.y = newAmount; break; case BarDirections.UpToDown: _targetLocalScale.y = 1f - newAmount; break; } bar.localScale = _targetLocalScale; break; case FillModes.Width: if (image == null) { return; } float newSizeX = MMMaths.Remap(newAmount, 0f, 1f, 0, initialSize.x); image.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, newSizeX); break; case FillModes.Height: if (image == null) { return; } float newSizeY = MMMaths.Remap(newAmount, 0f, 1f, 0, initialSize.y); image.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, newSizeY); break; case FillModes.FillAmount: if (image == null) { return; } image.fillAmount = newAmount; break; case FillModes.Anchor: if (image == null) { return; } switch (BarDirection) { case BarDirections.LeftToRight: _anchorVector.x = 0f; _anchorVector.y = 0f; image.rectTransform.anchorMin = _anchorVector; _anchorVector.x = newAmount; _anchorVector.y = 1f; image.rectTransform.anchorMax = _anchorVector; break; case BarDirections.RightToLeft: _anchorVector.x = newAmount; _anchorVector.y = 0f; image.rectTransform.anchorMin = _anchorVector; _anchorVector.x = 1f; _anchorVector.y = 1f; image.rectTransform.anchorMax = _anchorVector; break; case BarDirections.DownToUp: _anchorVector.x = 0f; _anchorVector.y = 0f; image.rectTransform.anchorMin = _anchorVector; _anchorVector.x = 1f; _anchorVector.y = newAmount; image.rectTransform.anchorMax = _anchorVector; break; case BarDirections.UpToDown: _anchorVector.x = 0f; _anchorVector.y = newAmount; image.rectTransform.anchorMin = _anchorVector; _anchorVector.x = 1f; _anchorVector.y = 1f; image.rectTransform.anchorMax = _anchorVector; break; } break; } } #region Bump /// /// Triggers a camera bump /// public virtual void Bump() { bool shouldBump = false; if (!_initialized) { return; } DetermineDirection(); if (BumpOnIncrease && (_direction > 0)) { shouldBump = true; } if (BumpOnDecrease && (_direction < 0)) { shouldBump = true; } if (BumpScaleOnChange) { shouldBump = true; } if (!shouldBump) { return; } if (this.gameObject.activeInHierarchy) { StartCoroutine(BumpCoroutine()); } OnBump?.Invoke(); } /// /// A coroutine that (usually quickly) changes the scale of the bar /// /// The coroutine. protected virtual IEnumerator BumpCoroutine() { float journey = 0f; Bumping = true; while (journey <= BumpDuration) { journey = journey + _deltaTime; float percent = Mathf.Clamp01(journey / BumpDuration); float curvePercent = BumpScaleAnimationCurve.Evaluate(percent); float colorCurvePercent = BumpColorAnimationCurve.Evaluate(percent); this.transform.localScale = curvePercent * _initialScale; if (ChangeColorWhenBumping && _isForegroundImageNotNull) { _foregroundImage.color = Color.Lerp(_initialColor, BumpColor, colorCurvePercent); } yield return null; } if (ChangeColorWhenBumping && _isForegroundImageNotNull) { _foregroundImage.color = _initialColor; } Bumping = false; yield return null; } #endregion Bump #region ShowHide /// /// A simple method you can call to show the bar (set active true) /// public virtual void ShowBar() { this.gameObject.SetActive(true); } /// /// Hides (SetActive false) the progress bar object, after an optional delay /// /// public virtual void HideBar(float delay) { if (delay <= 0) { this.gameObject.SetActive(false); } else if (this.gameObject.activeInHierarchy) { StartCoroutine(HideBarCo(delay)); } } /// /// An internal coroutine used to handle the disabling of the progress bar after a delay /// /// /// protected virtual IEnumerator HideBarCo(float delay) { yield return MMCoroutine.WaitFor(delay); this.gameObject.SetActive(false); } #endregion ShowHide } }