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

280 lines
9.7 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
namespace DuloGames.UI
{
[AddComponentMenu("UI/Bars/Bullet Bar"), RequireComponent(typeof(RectTransform))]
public class UIBulletBar : UIBehaviour, IUIProgressBar
{
public enum BarType
{
Horizontal,
Vertical,
Radial
}
[SerializeField] private BarType m_BarType = BarType.Horizontal;
[SerializeField] private bool m_FixedSize = false;
[SerializeField] private Vector2 m_BulletSize = Vector2.zero;
[SerializeField] private Sprite m_BulletSprite;
[SerializeField] private Color m_BulletSpriteColor = Color.white;
[SerializeField] private Sprite m_BulletSpriteActive;
[SerializeField] private Color m_BulletSpriteActiveColor = Color.white;
[SerializeField] private float m_SpriteRotation = 0f;
[SerializeField] private Vector2 m_ActivePosition = Vector2.zero;
[SerializeField][Range(0f, 360f)] private float m_AngleMin = 0f;
[SerializeField][Range(0f, 360f)] private float m_AngleMax = 360f;
[SerializeField] private int m_BulletCount = 10;
[SerializeField] private float m_Distance = 100f;
[SerializeField][Range(0f, 1f)] private float m_FillAmount = 1f;
[SerializeField] private bool m_InvertFill = true;
[SerializeField][HideInInspector] private GameObject m_BulletsContainer;
[SerializeField][HideInInspector] private List<GameObject> m_FillBullets;
/// <summary>
/// Gets or sets the fill amount (0 to 1).
/// </summary>
public float fillAmount
{
get { return this.m_FillAmount; }
set {
this.m_FillAmount = Mathf.Clamp01(value);
this.UpdateFill();
}
}
/// <summary>
/// Gets or sets value indicating whether the fill should be inverted.
/// </summary>
public bool invertFill
{
get { return this.m_InvertFill; }
set {
this.m_InvertFill = value;
this.UpdateFill();
}
}
/// <summary>
/// Gets the rect transform.
/// </summary>
public RectTransform rectTransform
{
get { return this.transform as RectTransform; }
}
protected override void Start()
{
base.Start();
if (this.m_BulletSprite == null || this.m_BulletSpriteActive == null)
{
Debug.LogWarning("The Bullet Bar script on game object " + this.gameObject.name + " requires that both bullet sprites are assigned to work.");
this.enabled = false;
return;
}
// Check if the bullets are constructed
if (this.m_BulletsContainer == null)
{
this.ConstructBullets();
}
}
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
// Update the bar fill
this.UpdateFill();
}
#endif
/// <summary>
/// Updates the fill.
/// </summary>
public void UpdateFill()
{
if (!this.isActiveAndEnabled || this.m_FillBullets == null || this.m_FillBullets.Count == 0)
return;
GameObject[] list = this.m_FillBullets.ToArray();
if (this.m_InvertFill)
{
System.Array.Reverse(list);
}
int index = 0;
foreach (GameObject go in list)
{
float currentPct = (float)index / (float)this.m_BulletCount;
Image img = go.GetComponent<Image>();
if (img != null)
{
img.enabled = (this.m_FillAmount > 0f && currentPct <= this.m_FillAmount);
}
index++;
}
}
/// <summary>
/// Constructs the bullet game objects and components.
/// </summary>
public void ConstructBullets()
{
if (this.m_BulletSprite == null || this.m_BulletSpriteActive == null || !this.isActiveAndEnabled)
return;
// Destroy the old bullets
this.DestroyBullets();
// Create the container
this.m_BulletsContainer = new GameObject("Bullets", typeof(RectTransform));
this.m_BulletsContainer.transform.SetParent(this.transform);
this.m_BulletsContainer.layer = this.gameObject.layer;
RectTransform crt = this.m_BulletsContainer.transform as RectTransform;
crt.localScale = new Vector3(1f, 1f, 1f);
crt.sizeDelta = this.rectTransform.sizeDelta;
crt.localPosition = Vector3.zero;
crt.anchoredPosition = Vector2.zero;
// Create new bullets
for (int i = 0; i < this.m_BulletCount; i++)
{
float pct = (float)i / (float)this.m_BulletCount;
// Create the background
GameObject obj = new GameObject("Bullet " + i.ToString(), typeof(RectTransform));
obj.transform.SetParent(this.m_BulletsContainer.transform);
obj.layer = this.gameObject.layer;
RectTransform rt = obj.transform as RectTransform;
rt.localScale = new Vector3(1f, 1f, 1f);
rt.localPosition = Vector3.zero;
Image img = obj.AddComponent<Image>();
img.sprite = this.m_BulletSprite;
img.color = this.m_BulletSpriteColor;
if (this.m_FixedSize)
rt.sizeDelta = this.m_BulletSize;
else
img.SetNativeSize();
// Position the bullet
if (this.m_BarType == BarType.Radial)
{
float ang = (this.m_AngleMin + (pct * (this.m_AngleMax - this.m_AngleMin)));
Vector2 pos;
pos.x = 0f + this.m_Distance * Mathf.Sin(ang * Mathf.Deg2Rad);
pos.y = 0f + this.m_Distance * Mathf.Cos(ang * Mathf.Deg2Rad);
rt.anchoredPosition = pos;
rt.Rotate(new Vector3(0f, 0f, ((this.m_SpriteRotation + ang) * -1f)));
}
else if (this.m_BarType == BarType.Horizontal)
{
rt.pivot = new Vector2(0.5f, 0.5f);
rt.anchorMin = new Vector2(1f, 0.5f);
rt.anchorMax = new Vector2(1f, 0.5f);
float occupiedSpace = rt.sizeDelta.x * this.m_BulletCount;
float freeSpace = this.rectTransform.rect.width - occupiedSpace;
float spacing = freeSpace / (this.m_BulletCount - 1);
float offsetX = (rt.sizeDelta.x * i) + (spacing * i);
Vector2 pos;
pos.x = (offsetX + (rt.sizeDelta.x / 2f)) * -1f;
pos.y = 0f;
rt.anchoredPosition = pos;
rt.Rotate(new Vector3(0f, 0f, this.m_SpriteRotation));
}
else if (this.m_BarType == BarType.Vertical)
{
rt.pivot = new Vector2(0.5f, 0.5f);
rt.anchorMin = new Vector2(0.5f, 1f);
rt.anchorMax = new Vector2(0.5f, 1f);
float occupiedSpace = rt.sizeDelta.y * this.m_BulletCount;
float freeSpace = this.rectTransform.rect.height - occupiedSpace;
float spacing = freeSpace / (this.m_BulletCount - 1);
float offsetY = (rt.sizeDelta.y * i) + (spacing * i);
Vector2 pos;
pos.x = 0f;
pos.y = (offsetY + (rt.sizeDelta.y / 2f)) * -1f;
rt.anchoredPosition = pos;
rt.Rotate(new Vector3(0f, 0f, this.m_SpriteRotation));
}
// Create the fill
GameObject objFill = new GameObject("Fill", typeof(RectTransform));
objFill.transform.SetParent(obj.transform);
objFill.layer = this.gameObject.layer;
RectTransform rtFill = objFill.transform as RectTransform;
rtFill.localScale = new Vector3(1f, 1f, 1f);
rtFill.localPosition = Vector3.zero;
rtFill.anchoredPosition = this.m_ActivePosition;
rtFill.rotation = rt.rotation;
Image imgFill = objFill.AddComponent<Image>();
imgFill.sprite = this.m_BulletSpriteActive;
imgFill.color = this.m_BulletSpriteActiveColor;
if (this.m_FixedSize)
rtFill.sizeDelta = this.m_BulletSize;
else
imgFill.SetNativeSize();
// Add the fill bullet to the list
this.m_FillBullets.Add(objFill);
}
// Update
this.UpdateFill();
}
protected void DestroyBullets()
{
// Clear the list
this.m_FillBullets.Clear();
GameObject go = this.m_BulletsContainer;
// Destroy bullets
if (Application.isEditor)
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.delayCall += () =>
{
DestroyImmediate(go);
};
#endif
}
else Destroy(go);
// Null the variable
this.m_BulletsContainer = null;
}
}
}