2026-05-06 15:07:56 +02:00

281 lines
7.4 KiB
C#

using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
namespace DuloGames.UI
{
[AddComponentMenu("UI/Bars/Progress Bar")]
public class UIProgressBar : MonoBehaviour, IUIProgressBar
{
[Serializable] public class ChangeEvent : UnityEvent<float> { }
public enum Type
{
Filled,
Resize,
Sprites
}
public enum FillSizing
{
Parent,
Fixed
}
[SerializeField] private Type m_Type = Type.Filled;
[SerializeField] private Image m_TargetImage;
[SerializeField] private Sprite[] m_Sprites;
[SerializeField] private RectTransform m_TargetTransform;
[SerializeField] private FillSizing m_FillSizing = FillSizing.Parent;
[SerializeField] private float m_MinWidth = 0f;
[SerializeField] private float m_MaxWidth = 100f;
[SerializeField][Range(0f, 1f)] private float m_FillAmount = 1f;
[SerializeField] private int m_Steps = 0;
public ChangeEvent onChange = new ChangeEvent();
/// <summary>
/// Gets or sets the type.
/// </summary>
/// <value>The type.</value>
public Type type {
get { return this.m_Type; }
set { this.m_Type = value; }
}
/// <summary>
/// Gets or sets the target image.
/// </summary>
/// <value>The target image.</value>
public Image targetImage {
get { return this.m_TargetImage; }
set { this.m_TargetImage = value; }
}
/// <summary>
/// Gets or sets array with the animation sprites.
/// </summary>
public Sprite[] sprites
{
get { return this.m_Sprites; }
set { this.m_Sprites = value; }
}
/// <summary>
/// Gets or sets the target transform.
/// </summary>
/// <value>The target transform.</value>
public RectTransform targetTransform {
get { return this.m_TargetTransform; }
set { this.m_TargetTransform = value; }
}
/// <summary>
/// Gets or sets the minimum width (Used for the resize type bar).
/// </summary>
/// <value>The minimum width.</value>
public float minWidth {
get { return this.m_MinWidth; }
set {
this.m_MinWidth = value;
this.UpdateBarFill();
}
}
/// <summary>
/// Gets or sets the maximum width (Used for the resize type bar).
/// </summary>
/// <value>The maximum width.</value>
public float maxWidth {
get { return this.m_MaxWidth; }
set {
this.m_MaxWidth = value;
this.UpdateBarFill();
}
}
/// <summary>
/// Gets or sets the fill amount.
/// </summary>
/// <value>The fill amount.</value>
public float fillAmount {
get {
return this.m_FillAmount;
}
set {
if (this.m_FillAmount != Mathf.Clamp01(value))
{
this.m_FillAmount = Mathf.Clamp01(value);
this.UpdateBarFill();
this.onChange.Invoke(this.m_FillAmount);
}
}
}
/// <summary>
/// Gets or sets the steps (Zero for no stepping).
/// </summary>
/// <value>The steps.</value>
public int steps {
get { return this.m_Steps; }
set { this.m_Steps = value; }
}
/// <summary>
/// Gets or sets the current step.
/// </summary>
/// <value>The current step.</value>
public int currentStep {
get {
if (this.m_Steps == 0)
return 0;
float perStep = 1f / (this.m_Steps - 1);
return Mathf.RoundToInt(this.fillAmount / perStep);
}
set {
if (this.m_Steps > 0)
{
float perStep = 1f / (this.m_Steps - 1);
this.fillAmount = Mathf.Clamp(value, 0, this.m_Steps) * perStep;
}
}
}
protected virtual void Start()
{
// Make sure the fill anchor reflects the pivot
if (this.m_Type == Type.Resize && this.m_FillSizing == FillSizing.Parent && this.m_TargetTransform != null)
{
float height = this.m_TargetTransform.rect.height;
this.m_TargetTransform.anchorMin = this.m_TargetTransform.pivot;
this.m_TargetTransform.anchorMax = this.m_TargetTransform.pivot;
this.m_TargetTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
}
// Update the bar fill
this.UpdateBarFill();
}
protected virtual void OnRectTransformDimensionsChange()
{
// Update the bar fill
this.UpdateBarFill();
}
#if UNITY_EDITOR
protected void OnValidate()
{
// Make sure the fill anchor reflects the pivot
if (this.m_Type == Type.Resize && this.m_FillSizing == FillSizing.Parent && this.m_TargetTransform != null)
{
float height = this.m_TargetTransform.rect.height;
this.m_TargetTransform.anchorMin = this.m_TargetTransform.pivot;
this.m_TargetTransform.anchorMax = this.m_TargetTransform.pivot;
this.m_TargetTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
}
}
protected void Reset()
{
this.onChange = new ChangeEvent();
}
#endif
/// <summary>
/// Updates the bar fill.
/// </summary>
public void UpdateBarFill()
{
if (!this.isActiveAndEnabled)
return;
if (this.m_Type == Type.Filled && this.m_TargetImage == null)
return;
if (this.m_Type == Type.Resize && this.m_TargetTransform == null)
return;
if (this.m_Type == Type.Sprites && this.m_Sprites.Length == 0)
return;
// Get the fill amount
float fill = this.m_FillAmount;
// Check for steps
if (this.m_Steps > 0)
fill = Mathf.Round(this.m_FillAmount * (this.m_Steps - 1)) / (this.m_Steps - 1);
if (this.m_Type == Type.Resize)
{
// Update the bar fill by changing it's width
// we are doing it this way because we are using a mask on the bar and have it's fill inside with static width and position
if (this.m_FillSizing == FillSizing.Fixed)
{
this.m_TargetTransform.SetSizeWithCurrentAnchors(
RectTransform.Axis.Horizontal,
(this.m_MinWidth + ((this.m_MaxWidth - this.m_MinWidth) * fill))
);
}
else
{
this.m_TargetTransform.SetSizeWithCurrentAnchors(
RectTransform.Axis.Horizontal,
((this.m_TargetTransform.parent as RectTransform).rect.width * fill)
);
}
}
else if (this.m_Type == Type.Sprites)
{
int spriteIndex = Mathf.RoundToInt(fill * (float)this.m_Sprites.Length) - 1;
if (spriteIndex > -1)
{
this.targetImage.overrideSprite = this.m_Sprites[spriteIndex];
this.targetImage.canvasRenderer.SetAlpha(1f);
}
else
{
this.targetImage.overrideSprite = null;
this.targetImage.canvasRenderer.SetAlpha(0f);
}
}
else
{
// Update the image fill amount
this.m_TargetImage.fillAmount = fill;
}
}
/// <summary>
/// Adds to the fill (Used for buttons).
/// </summary>
public void AddFill()
{
if (this.m_Steps > 0)
{
this.currentStep = this.currentStep + 1;
}
else
{
this.fillAmount = this.fillAmount + 0.1f;
}
}
/// <summary>
/// Removes from the fill (Used for buttons).
/// </summary>
public void RemoveFill()
{
if (this.m_Steps > 0)
{
this.currentStep = this.currentStep - 1;
}
else
{
this.fillAmount = this.fillAmount - 0.1f;
}
}
}
}