321 lines
11 KiB
C#
321 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
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (_boosterDraggable != null)
|
|
{
|
|
_boosterDraggable.OnBoosterOpened -= HandleBoosterOpened;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|