using System; using System.Collections.Generic; using UnityEngine; namespace EnergyBarToolkit { [SelectionBase] [RequireComponent(typeof(EnergyBar))] [ExecuteInEditMode] public class RepeatedRendererUGUI : EnergyBarUGUIBase { public enum GrowType { None = 0, Grow = 1, Fade = 2, Fill = 3 } public enum BlinkOperator { LessThan = 0, LessOrEqual = 1, GreaterThan = 2, GreaterOrEqual = 3 } public SpriteTex spriteIcon = new SpriteTex(); public SpriteTex spriteSlot = new SpriteTex(); public int repeatCount = 5; public Vector2 repeatPositionDelta = new Vector2(32f, 0f); public GrowType growType; public GrowDirection growDirection; public bool effectBlink; public float effectBlinkValue = 0.2f; public float effectBlinkRatePerSecond = 1f; public Color effectBlinkColor = new Color(1f, 1f, 1f, 0f); public BlinkOperator effectBlinkOperator = BlinkOperator.LessOrEqual; [SerializeField] private int lastRebuildHash; private bool dirty; [SerializeField] private List slotImages = new List(32); [SerializeField] private List iconImages = new List(32); [SerializeField] private List originPositions = new List(32); [SerializeField] private Vector2 sizeOrigin; [SerializeField] private Vector2 scaleRatio = Vector2.one; private float _effectBlinkAccum; public bool forceBlinking { get; set; } private bool Blink { get; set; } private Color IconTintTransparent { get { return new Color(spriteIcon.color.r, spriteIcon.color.g, spriteIcon.color.g, 0f); } } public override void SetNativeSize() { if (spriteIcon == null) { Rebuild(); if (spriteIcon == null) { Debug.LogWarning("Cannot resize bar that has not been created yet"); return; } } Vector2 size = ComputeNativeSize(); SetSize(rectTransform, size); } private Vector2 ComputeNativeSize() { if (spriteIcon.sprite == null) { return Vector2.zero; } int num = Mathf.RoundToInt(spriteIcon.sprite.rect.width); int num2 = Mathf.RoundToInt(spriteIcon.sprite.rect.height); int num3 = (int)((float)num + Mathf.Abs(repeatPositionDelta.x * (float)(repeatCount - 1))); int num4 = (int)((float)num2 + Mathf.Abs(repeatPositionDelta.y * (float)(repeatCount - 1))); return new Vector2(num3, num4); } public Image2 GetIconImage(int index) { return iconImages[index]; } public Image2 GetSlotImage(int index) { return slotImages[index]; } public int GetIconCount() { return repeatCount; } public int GetFullyVisibleIconCount() { float f = ValueF2 * (float)repeatCount; return (int)Mathf.Floor(f); } public int GetVisibleIconCount() { float f = ValueF2 * (float)repeatCount; return (int)Mathf.Ceil(f); } protected override void Update() { base.Update(); UpdateRebuild(); UpdateBar(); UpdateBlinkEffect(); UpdateVisible(); UpdateSize(); } private void OnValidate() { repeatCount = Mathf.Max(1, repeatCount); } private void UpdateBar() { if (iconImages.Count == 0) { return; } float num = ValueF2 * (float)repeatCount; int num2 = (int)Mathf.Floor(num); float num3 = num - (float)num2; for (int i = 0; i < repeatCount; i++) { Image2 image = iconImages[i]; if (slotImages.Count > 0) { Image2 image2 = slotImages[i]; UpdateSlot(image2); } if (i < num2) { SetIconVisible(image); continue; } if (i > num2) { SetIconInvisible(image); continue; } switch (growType) { case GrowType.None: if (Mathf.Approximately(num3, 0f)) { SetIconInvisible(image); } else { SetIconVisible(image); } break; case GrowType.Fade: SetIconVisible(image); image.color = Color.Lerp(IconTintTransparent, spriteIcon.color, num3); break; case GrowType.Grow: SetIconVisible(image, num3); break; case GrowType.Fill: SetIconVisible(image); image.growDirection = growDirection; image.fillValue = num3; break; default: Debug.Log("Unknown grow type: " + growType); break; } } } private void UpdateSize() { if (!(spriteIcon.sprite == null)) { Vector2 vector = ComputeNativeSize(); Vector2 size = rectTransform.rect.size; scaleRatio = new Vector2(size.x / vector.x, size.y / vector.y); Rect rect = spriteIcon.sprite.rect; for (int i = 0; i < iconImages.Count; i++) { Vector2 originPosition = originPositions[i]; Image2 image = iconImages[i]; UpdateSpriteSize(originPosition, image, rect); } for (int j = 0; j < slotImages.Count; j++) { Vector2 originPosition2 = originPositions[j]; Image2 image2 = slotImages[j]; UpdateSpriteSize(originPosition2, image2, rect); } } } private void UpdateSpriteSize(Vector2 originPosition, Image2 image, Rect spriteRect) { float x = originPosition.x * scaleRatio.x; float y = originPosition.y * scaleRatio.y; MadTransform.SetLocalPosition(image.rectTransform, new Vector3(x, y)); SetSize(image.rectTransform, new Vector2(spriteRect.width * scaleRatio.x, spriteRect.height * scaleRatio.y)); } private void SetIconVisible(Image2 image, float scale = 1f) { image.color = ComputeColor(spriteIcon.color); image.fillValue = 1f; MadTransform.SetLocalScale(image.transform, new Vector3(scale, scale, scale)); image.enabled = true; } private void UpdateSlot(Image2 image) { if (image != null) { image.color = ComputeColor(spriteSlot.color); } } private void SetIconInvisible(Image2 image) { image.enabled = false; } private void UpdateVisible() { if (!IsVisible()) { for (int i = 0; i < iconImages.Count; i++) { Image2 image = iconImages[i]; image.enabled = false; } for (int j = 0; j < slotImages.Count; j++) { Image2 image2 = slotImages[j]; image2.enabled = false; } } else if (Blink) { for (int k = 0; k < iconImages.Count; k++) { Image2 image3 = iconImages[k]; image3.enabled = false; } } } private void UpdateBlinkEffect() { if (forceBlinking) { Blink = EnergyBarCommons.Blink(effectBlinkRatePerSecond, ref _effectBlinkAccum); } else if (CanBlink()) { Blink = EnergyBarCommons.Blink(effectBlinkRatePerSecond, ref _effectBlinkAccum); } else { Blink = false; } } private bool CanBlink() { if (!effectBlink) { return false; } switch (effectBlinkOperator) { case BlinkOperator.LessThan: return ValueF2 < effectBlinkValue; case BlinkOperator.LessOrEqual: return ValueF2 <= effectBlinkValue; case BlinkOperator.GreaterThan: return ValueF2 > effectBlinkValue; case BlinkOperator.GreaterOrEqual: return ValueF2 >= effectBlinkValue; default: throw new ArgumentOutOfRangeException(); } } private void UpdateRebuild() { if (RebuildNeeded()) { Rebuild(); } } private bool RebuildNeeded() { if (iconImages.Count == 0 && spriteIcon != null && repeatCount != 0) { return true; } if (iconImages.Count > 0 && iconImages[0] == null) { return true; } int currentHash = 37; currentHash = MadHashCode.Add(currentHash, spriteIcon); currentHash = MadHashCode.Add(currentHash, spriteSlot); currentHash = MadHashCode.Add(currentHash, repeatCount); currentHash = MadHashCode.Add(currentHash, repeatPositionDelta); currentHash = MadHashCode.Add(currentHash, rectTransform.pivot); if (currentHash != lastRebuildHash || dirty) { lastRebuildHash = currentHash; dirty = false; return true; } return false; } private void Rebuild() { RemoveCreatedChildren(); iconImages.Clear(); slotImages.Clear(); originPositions.Clear(); BuildIconsAndSlots(); MoveLabelToTop(); } private void BuildIconsAndSlots() { Vector2 min = Vector2.zero; Vector2 max = Vector2.zero; bool hasMinMax = false; for (int i = 0; i < repeatCount; i++) { if (spriteSlot.sprite != null) { Image2 image = CreateChild(string.Format("slot_{0:D2}", i + 1)); image.sprite = spriteSlot.sprite; image.color = spriteSlot.color; image.material = spriteSlot.material; image.transform.localPosition = repeatPositionDelta * i; slotImages.Add(image); Expand(ref min, ref max, ref hasMinMax, image.rectTransform); } if (spriteIcon.sprite != null) { Image2 image2 = CreateChild(string.Format("icon_{0:D2}", i + 1)); image2.sprite = spriteIcon.sprite; image2.color = spriteIcon.color; image2.material = spriteIcon.material; image2.transform.localPosition = repeatPositionDelta * i; iconImages.Add(image2); Expand(ref min, ref max, ref hasMinMax, image2.rectTransform); } } sizeOrigin = ComputeNativeSize(); SetNativeSize(); Vector2 vector = new Vector2(0.5f * sizeOrigin.x - rectTransform.pivot.x * sizeOrigin.x, 0.5f * sizeOrigin.y - rectTransform.pivot.y * sizeOrigin.y); Vector2 vector2 = -repeatPositionDelta * (repeatCount - 1) * 0.5f; for (int j = 0; j < slotImages.Count; j++) { Image2 image3 = slotImages[j]; image3.rectTransform.localPosition = repeatPositionDelta * j + (vector2 + vector); } for (int k = 0; k < iconImages.Count; k++) { Image2 image4 = iconImages[k]; image4.rectTransform.localPosition = repeatPositionDelta * k + (vector2 + vector); originPositions.Add(image4.rectTransform.localPosition); } if (scaleRatio != Vector2.one) { Vector2 size = rectTransform.rect.size; size.x *= scaleRatio.x; size.y *= scaleRatio.y; SetSize(rectTransform, size); UpdateSize(); } } private void Expand(ref Vector2 min, ref Vector2 max, ref bool hasMinMax, RectTransform tr) { Rect rect = tr.rect; float num = rect.xMin + tr.localPosition.x; float num2 = rect.xMax + tr.localPosition.x; float num3 = rect.yMin + tr.localPosition.y; float num4 = rect.yMax + tr.localPosition.y; if (!hasMinMax) { min.x = num; min.y = num3; max.x = num2; max.y = num4; hasMinMax = true; return; } if (num < min.x) { min.x = num; } if (num3 < min.y) { min.y = num3; } if (num2 > max.x) { max.x = num2; } if (num4 > max.y) { max.y = num4; } } } }