Files
AppleHillsProduction/Assets/Scripts/UI/CardSystem/DragDrop/BoosterPackVisual.cs
2025-11-11 12:32:36 +00:00

323 lines
11 KiB
C#

using Pixelplacement;
using Pixelplacement.TweenSystem;
using UI.DragAndDrop.Core;
using UnityEngine;
using UnityEngine.UI;
namespace UI.CardSystem.DragDrop
{
/// <summary>
/// Visual representation for BoosterPackDraggable.
/// Displays the booster pack sprite and handles opening animations.
/// </summary>
public class BoosterPackVisual : DraggableVisual
{
[Header("Booster Pack Visual")]
[SerializeField] private Image packImage;
[SerializeField] private Sprite packSprite;
[SerializeField] private ParticleSystem glowEffect;
[SerializeField] private Transform glowTransform;
[Header("Opening Animation")]
[SerializeField] private float openingScalePunch = 0.5f;
[SerializeField] private float openingRotationPunch = 360f;
[SerializeField] private float openingDuration = 0.5f;
private BoosterPackDraggable _boosterDraggable;
// Effect tracking
private int _glowRotationTweenId = -1;
private float _defaultGlowRate = 10f;
public override void Initialize(DraggableObject parent)
{
base.Initialize(parent);
_boosterDraggable = parent as BoosterPackDraggable;
// Get pack image if not assigned
if (packImage == null)
{
packImage = GetComponentInChildren<Image>();
}
// Set initial sprite
if (packImage != null && packSprite != null)
{
packImage.sprite = packSprite;
}
// Subscribe to booster events
if (_boosterDraggable != null)
{
_boosterDraggable.OnBoosterOpened += HandleBoosterOpened;
_boosterDraggable.OnTapped += HandleTapped;
}
// Start glow effect if available
if (glowEffect != null && !glowEffect.isPlaying)
{
glowEffect.Play();
}
}
protected override void UpdateVisualContent()
{
// Update glow rotation for visual interest (skip if effects suppressed)
if (glowTransform != null && !_effectsSuppressed)
{
glowTransform.Rotate(Vector3.forward * 30f * Time.deltaTime);
}
}
private void HandleBoosterOpened(BoosterPackDraggable booster)
{
PlayOpeningAnimation();
}
private void HandleTapped(BoosterPackDraggable booster, int currentTap, int maxTaps)
{
PlayShakeAnimation(currentTap, maxTaps);
}
/// <summary>
/// Play progressive shake animation based on tap intensity
/// This is always allowed, even when effects are suppressed
/// </summary>
public void PlayShakeAnimation(int intensity, int maxIntensity)
{
float normalizedIntensity = (float)intensity / maxIntensity;
float shakeAmount = Mathf.Lerp(5f, 30f, normalizedIntensity);
float shakeDuration = 0.15f;
// Shake rotation
Vector3 shakeRotation = new Vector3(
Random.Range(-shakeAmount, shakeAmount),
Random.Range(-shakeAmount, shakeAmount),
Random.Range(-shakeAmount, shakeAmount)
);
Tween.Rotation(transform, transform.eulerAngles + shakeRotation,
shakeDuration, 0f, Tween.EaseOutBack,
completeCallback: () => {
Tween.Rotation(transform, Vector3.zero,
shakeDuration, 0f, Tween.EaseInBack);
});
// NOTE: Scale pulse is handled by BoosterPackDraggable.OnPointerUpHook()
// We don't need a duplicate scale tween here - it would conflict!
// Extra glow burst on final tap (only if effects not suppressed)
if (intensity == maxIntensity && glowEffect != null && !_effectsSuppressed)
{
var emission = glowEffect.emission;
emission.rateOverTimeMultiplier = 50f;
}
}
/// <summary>
/// Play the booster pack opening animation
/// </summary>
public void PlayOpeningAnimation()
{
// Scale punch
Vector3 targetScale = transform.localScale * (1f + openingScalePunch);
Tween.LocalScale(transform, targetScale, openingDuration / 2f, 0f, Tween.EaseOutBack,
completeCallback: () => {
Tween.LocalScale(transform, Vector3.one, openingDuration / 2f, 0f, Tween.EaseInBack);
});
// Rotation
Tween.Rotation(transform, transform.eulerAngles + Vector3.forward * openingRotationPunch,
openingDuration, 0f, Tween.EaseOutBack);
// Glow burst
if (glowEffect != null)
{
glowEffect.Stop();
glowEffect.Play();
}
}
/// <summary>
/// Set the booster pack sprite
/// </summary>
public void SetPackSprite(Sprite sprite)
{
packSprite = sprite;
if (packImage != null)
{
packImage.sprite = packSprite;
}
}
protected override void OnPointerEnterVisual()
{
base.OnPointerEnterVisual();
// Extra glow when hovering (skip if effects suppressed)
if (glowEffect != null && !_effectsSuppressed)
{
var emission = glowEffect.emission;
emission.rateOverTimeMultiplier = 20f;
}
}
protected override void OnPointerExitVisual()
{
base.OnPointerExitVisual();
// Restore normal glow (skip if effects suppressed)
if (glowEffect != null && !_effectsSuppressed)
{
var emission = glowEffect.emission;
emission.rateOverTimeMultiplier = _defaultGlowRate;
}
}
#region Effect Management Overrides
protected override void OnEffectsSuppressed()
{
base.OnEffectsSuppressed();
// Stop glow effect
if (glowEffect != null)
{
glowEffect.Stop();
}
// Cancel glow rotation tween if tracked
if (_glowRotationTweenId != -1)
{
Tween.Stop(_glowRotationTweenId);
_glowRotationTweenId = -1;
}
// Reset glow rotation to zero
if (glowTransform != null)
{
glowTransform.localRotation = Quaternion.identity;
}
}
protected override void OnEffectsResumed()
{
base.OnEffectsResumed();
// Resume glow effect
if (glowEffect != null && !glowEffect.isPlaying)
{
glowEffect.Play();
}
}
protected override void OnEffectsReset()
{
base.OnEffectsReset();
// Stop glow effect
if (glowEffect != null)
{
glowEffect.Stop();
}
// Reset glow rotation
if (glowTransform != null)
{
glowTransform.localRotation = Quaternion.identity;
}
// NOTE: Tap pulse scale is handled by BoosterPackDraggable, not here
}
#endregion
#region Event Handler Overrides (Block when in Opening Slot)
protected override void HandleDragStarted(DraggableObject draggable)
{
// Don't call base if effects are suppressed (in opening slot)
if (_effectsSuppressed)
return;
base.HandleDragStarted(draggable);
}
protected override void HandleDragEnded(DraggableObject draggable)
{
// ALWAYS reset canvas sorting, even when effects are suppressed
if (canvas != null)
{
canvas.overrideSorting = false;
}
// Skip other drag end effects if suppressed (in opening slot)
if (_effectsSuppressed)
return;
base.HandleDragEnded(draggable);
}
protected override void HandlePointerEnter(DraggableObject draggable)
{
// Don't call base if effects are suppressed (in opening slot)
if (_effectsSuppressed)
return;
base.HandlePointerEnter(draggable);
}
protected override void HandlePointerExit(DraggableObject draggable)
{
// Don't call base if effects are suppressed (in opening slot)
if (_effectsSuppressed)
return;
base.HandlePointerExit(draggable);
}
protected override void HandlePointerDown(DraggableObject draggable)
{
// Don't call base if effects are suppressed (in opening slot)
// This allows the BoosterPackDraggable to handle tap pulse itself
if (_effectsSuppressed)
return;
base.HandlePointerDown(draggable);
}
protected override void HandlePointerUp(DraggableObject draggable, bool longPress)
{
// Don't call base if effects are suppressed (in opening slot)
// This allows the BoosterPackDraggable to handle tap pulse itself
if (_effectsSuppressed)
return;
base.HandlePointerUp(draggable, longPress);
}
protected override void HandleSelection(DraggableObject draggable, bool selected)
{
// Don't call base if effects are suppressed (in opening slot)
if (_effectsSuppressed)
return;
base.HandleSelection(draggable, selected);
}
#endregion
protected override void OnDestroy()
{
base.OnDestroy();
if (_boosterDraggable != null)
{
_boosterDraggable.OnBoosterOpened -= HandleBoosterOpened;
}
}
}
}