Files
AppleHillsProduction/Assets/Scripts/UI/CardSystem/BoosterPackGiver.cs
2025-10-21 15:40:47 +02:00

220 lines
8.2 KiB
C#

using System.Collections;
using Data.CardSystem;
using UnityEngine;
using UnityEngine.Events;
namespace UI.CardSystem
{
/// <summary>
/// One-off helper to visually grant a booster pack.
/// Place this on a UI GameObject with two Image children (a background "glow" and a booster pack image).
/// Access via BoosterPackGiver.Instance and call GiveBoosterPack().
/// The sequence:
/// 1) Shows the object (enables children)
/// 2) Pulses the glow scale for a fixed duration
/// 3) Hides the glow, tweens the booster image towards the backpack icon and scales to zero
/// 4) Invokes OnCompleted
/// </summary>
public class BoosterPackGiver : MonoBehaviour
{
public static BoosterPackGiver Instance { get; private set; }
[Header("References")]
[Tooltip("Canvas that contains these UI elements. If null, will search up the hierarchy.")]
[SerializeField] private Canvas canvas;
[Tooltip("Background glow RectTransform (child image)")]
[SerializeField] private RectTransform backgroundGlow;
[Tooltip("Booster pack image RectTransform (child image)")]
[SerializeField] private RectTransform boosterImage;
[Tooltip("Target RectTransform for the backpack icon (where the booster flies to)")]
[SerializeField] private RectTransform targetBackpackIcon;
[Header("Timing")]
[Tooltip("How long the glow should pulse before the booster flies to the backpack")]
[SerializeField] private float pulseDuration = 2.0f;
[Tooltip("Duration of the flight/scale-down animation")]
[SerializeField] private float moveDuration = 0.6f;
[Header("Glow Pulse")]
[Tooltip("Minimum scale during pulse")] [SerializeField] private float glowScaleMin = 0.9f;
[Tooltip("Maximum scale during pulse")] [SerializeField] private float glowScaleMax = 1.1f;
[Tooltip("Pulse speed in cycles per second")] [SerializeField] private float glowPulseSpeed = 2.0f;
[Header("Move/Scale Easing")]
[SerializeField] private AnimationCurve moveCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
[SerializeField] private AnimationCurve scaleCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
[Header("Behaviour")]
[Tooltip("Hide visuals when the sequence completes")] [SerializeField] private bool hideOnComplete = true;
[Header("Events")]
public UnityEvent OnCompleted;
private Coroutine _sequenceCoroutine;
private Vector3 _boosterInitialScale;
private Vector2 _boosterInitialAnchoredPos;
private IEnumerator Start()
{
if (Instance != null && Instance != this)
{
Debug.LogWarning("[BoosterPackGiver] Duplicate instance detected. Destroying this component.");
Destroy(this);
yield break;
}
Instance = this;
if (canvas == null)
{
canvas = GetComponentInParent<Canvas>();
}
CacheInitialBoosterState();
// Start hidden (keep GameObject active so the singleton remains accessible)
SetVisualsActive(false);
// yield return new WaitForSeconds(1f);
// GiveBoosterPack();
}
private void OnDestroy()
{
if (Instance == this)
Instance = null;
}
private void CacheInitialBoosterState()
{
if (boosterImage != null)
{
_boosterInitialScale = boosterImage.localScale;
_boosterInitialAnchoredPos = boosterImage.anchoredPosition;
}
}
/// <summary>
/// Public entry point: run the grant animation.
/// </summary>
public void GiveBoosterPack()
{
if (backgroundGlow == null || boosterImage == null)
{
Debug.LogError("[BoosterPackGiver] Missing references. Assign Background Glow and Booster Image in the inspector.");
return;
}
// Reset and start fresh
if (_sequenceCoroutine != null)
{
StopCoroutine(_sequenceCoroutine);
_sequenceCoroutine = null;
}
// Ensure canvas reference
if (canvas == null)
{
canvas = GetComponentInParent<Canvas>();
}
// Reset booster transform
boosterImage.localScale = _boosterInitialScale;
boosterImage.anchoredPosition = _boosterInitialAnchoredPos;
// Show visuals
SetVisualsActive(true);
_sequenceCoroutine = StartCoroutine(RunSequence());
}
private IEnumerator RunSequence()
{
// 1) Pulse the glow
float elapsed = 0f;
Vector3 baseGlowScale = backgroundGlow.localScale;
while (elapsed < pulseDuration)
{
elapsed += Time.unscaledDeltaTime;
float t = Mathf.Sin(elapsed * Mathf.PI * 2f * glowPulseSpeed) * 0.5f + 0.5f; // 0..1
float s = Mathf.Lerp(glowScaleMin, glowScaleMax, t);
backgroundGlow.localScale = baseGlowScale * s;
yield return null;
}
// 2) Hide glow
backgroundGlow.gameObject.SetActive(false);
// 3) Move booster to backpack icon and scale to zero
Vector2 startPos = boosterImage.anchoredPosition;
Vector2 targetPos = startPos;
// Convert target to booster parent space if available
if (targetBackpackIcon != null)
{
var parentRect = boosterImage.parent as RectTransform;
if (parentRect != null)
{
Vector2 localPoint;
Vector2 screenPoint = RectTransformUtility.WorldToScreenPoint(canvas != null ? canvas.worldCamera : null, targetBackpackIcon.position);
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRect, screenPoint, canvas != null ? canvas.worldCamera : null, out localPoint))
{
targetPos = localPoint;
}
}
}
elapsed = 0f;
while (elapsed < moveDuration)
{
elapsed += Time.unscaledDeltaTime;
float t = Mathf.Clamp01(elapsed / moveDuration);
float mt = moveCurve != null ? moveCurve.Evaluate(t) : t;
float st = scaleCurve != null ? scaleCurve.Evaluate(t) : t;
boosterImage.anchoredPosition = Vector2.LerpUnclamped(startPos, targetPos, mt);
boosterImage.localScale = Vector3.LerpUnclamped(_boosterInitialScale, Vector3.zero, st);
yield return null;
}
// Ensure final state
boosterImage.anchoredPosition = targetPos;
boosterImage.localScale = Vector3.zero;
if (hideOnComplete)
{
SetVisualsActive(false);
// Restore booster for the next run
boosterImage.localScale = _boosterInitialScale;
boosterImage.anchoredPosition = _boosterInitialAnchoredPos;
backgroundGlow.localScale = Vector3.one; // reset pulse scaling
}
_sequenceCoroutine = null;
OnCompleted?.Invoke();
CardSystemManager.Instance.AddBoosterPack(1);
}
private void SetVisualsActive(bool active)
{
if (backgroundGlow != null) backgroundGlow.gameObject.SetActive(active);
if (boosterImage != null) boosterImage.gameObject.SetActive(active);
}
// Optional: quick editor hookup to validate references
#if UNITY_EDITOR
private void OnValidate()
{
if (canvas == null)
{
canvas = GetComponentInParent<Canvas>();
}
if (boosterImage != null && _boosterInitialScale == Vector3.zero)
{
_boosterInitialScale = boosterImage.localScale;
_boosterInitialAnchoredPos = boosterImage.anchoredPosition;
}
}
#endif
}
}