Files
AppleHillsProduction/Assets/Scripts/CardSystem/DragDrop/BoosterPackDraggable.cs
2025-11-19 22:56:24 +01:00

238 lines
9.4 KiB
C#

using Core;
using UI.DragAndDrop.Core;
using UnityEngine;
namespace UI.CardSystem.DragDrop
{
/// <summary>
/// Booster pack specific implementation of DraggableObject.
/// Manages booster pack behavior and opening logic.
/// </summary>
public class BoosterPackDraggable : DraggableObject
{
[Header("Booster Pack Settings")]
[SerializeField] private bool canOpenOnDrop = true;
[SerializeField] private bool canOpenOnDoubleClick = true;
[Header("Tap to Open")]
[SerializeField] private bool canTapToOpen = true;
[SerializeField] private int maxTapsToOpen = 3;
[SerializeField] private float tapPulseScale = 1.15f;
[SerializeField] private float tapPulseDuration = 0.2f;
// ...existing code...
public event System.Action<BoosterPackDraggable> OnBoosterOpened;
public event System.Action<BoosterPackDraggable, int, int> OnTapped; // (booster, currentTap, maxTaps)
public event System.Action<BoosterPackDraggable> OnReadyToOpen; // Final tap reached
private bool _isOpening;
private float _lastClickTime;
private int _currentTapCount;
public bool IsOpening => _isOpening;
public int CurrentTapCount => _currentTapCount;
protected override void OnPointerUpHook(bool longPress)
{
base.OnPointerUpHook(longPress);
// Handle tap-to-open logic (only when in slot and not a long press)
if (canTapToOpen && !longPress && CurrentSlot != null)
{
_currentTapCount++;
// Pulse effect on tap (scales visual up and back down)
if (Visual != null)
{
// Calculate pulse intensity based on tap progress
float tapProgress = _currentTapCount / (float)maxTapsToOpen;
float currentPulseScale = 1f + (tapPulseScale - 1f) * (0.5f + tapProgress * 0.5f); // Increases from 1.075 to 1.15
// Save the current scale before pulsing
Vector3 baseScale = Visual.transform.localScale;
Pixelplacement.Tween.Cancel(Visual.transform.GetInstanceID());
Pixelplacement.Tween.LocalScale(Visual.transform, baseScale * currentPulseScale, tapPulseDuration * 0.5f, 0f,
Pixelplacement.Tween.EaseOutBack, completeCallback: () =>
{
// Return to the base scale we had before pulsing
Pixelplacement.Tween.LocalScale(Visual.transform, baseScale, tapPulseDuration * 0.5f, 0f, Pixelplacement.Tween.EaseInBack);
});
}
OnTapped?.Invoke(this, _currentTapCount, maxTapsToOpen);
if (_currentTapCount >= maxTapsToOpen)
{
OnReadyToOpen?.Invoke(this);
}
return; // Don't process double-click if tap-to-open is active
}
// ...existing code...
if (canOpenOnDoubleClick && !longPress)
{
float timeSinceLastClick = Time.time - _lastClickTime;
if (timeSinceLastClick < 0.3f) // Double click threshold
{
TriggerOpen();
}
_lastClickTime = Time.time;
}
}
protected override void OnDragStartedHook()
{
base.OnDragStartedHook();
// Play pickup audio
AudioManager.Instance.LoadAndPlayUIAudio($"random_paper_pickup", false);
AudioManager.Instance.LoadAndPlayUIAudio($"shimmering_loop", true);
}
protected override void OnDragEndedHook()
{
base.OnDragEndedHook();
// Find closest slot and assign to it (replaces removed auto-slotting from base class)
SlotContainer[] containers = FindObjectsByType<SlotContainer>(FindObjectsSortMode.None);
DraggableSlot closestSlot = null;
float closestDistance = float.MaxValue;
// Get position (handle both overlay and world space canvas)
Vector3 myPosition = (RectTransform != null &&
GetComponentInParent<Canvas>()?.renderMode == RenderMode.ScreenSpaceOverlay)
? RectTransform.position
: transform.position;
// Find closest slot among all containers
foreach (var container in containers)
{
DraggableSlot slot = container.FindClosestSlot(myPosition, this);
if (slot != null)
{
Vector3 slotPosition = slot.RectTransform != null ? slot.RectTransform.position : slot.transform.position;
float distance = Vector3.Distance(myPosition, slotPosition);
if (distance < closestDistance)
{
closestDistance = distance;
closestSlot = slot;
}
}
}
// Assign to closest slot if found
if (closestSlot != null)
{
Logging.Debug($"[BoosterPackDraggable] Drag ended, assigning to closest slot: {closestSlot.name}");
AssignToSlot(closestSlot, true);
}
else if (CurrentSlot != null)
{
// No valid slot found, return to current slot
Logging.Debug($"[BoosterPackDraggable] No valid slot found, snapping back to current slot");
AssignToSlot(CurrentSlot, true);
}
// Play random put down paper audio
AudioManager.Instance.LoadAndPlayUIAudio($"random_paper_putdown", false);
// Stop the shimmer loop
AudioManager.Instance.uiMusicSource.Stop();
}
/// <summary>
/// Trigger the booster pack opening animation and logic
/// </summary>
public void TriggerOpen()
{
if (_isOpening)
return;
_isOpening = true;
OnBoosterOpened?.Invoke(this);
// The actual opening logic (calling CardSystemManager) should be handled
// by the UI page or controller that manages this booster pack
// Visual feedback would be handled by the BoosterPackVisual
}
/// <summary>
/// Reset the opening state
/// </summary>
public void ResetOpeningState()
{
_isOpening = false;
_currentTapCount = 0;
}
/// <summary>
/// Set whether this booster is in the opening slot (disables dragging, enables tapping)
/// </summary>
public void SetInOpeningSlot(bool inSlot)
{
Logging.Debug($"[BoosterPackDraggable] SetInOpeningSlot({inSlot}) called on {name}");
SetDraggingEnabled(!inSlot); // Disable dragging when in opening slot
Logging.Debug($"[BoosterPackDraggable] SetDraggingEnabled({!inSlot}) called");
canTapToOpen = inSlot; // Enable tap-to-open when in opening slot
if (inSlot)
{
_currentTapCount = 0; // Reset tap counter when placed
// Suppress visual effects (idle animations, glow, etc.) when in opening slot
// But allow slot tween and tap pulse to still work
if (Visual != null)
{
Visual.SuppressEffects();
// Play one-time placement tween to animate into slot
// The visual will follow the parent to its slot position, then lock in place
// Get target scale from current slot if it has scale mode
Vector3 targetScale = Vector3.one;
if (CurrentSlot != null && CurrentSlot.GetComponent<DraggableSlot>() != null)
{
// Access the slot's occupant scale if it's in Scale mode
// For now, use Vector3.one as default
targetScale = Vector3.one;
}
Visual.PlayPlacementTween(0.3f, targetScale);
}
}
else
{
ResetOpeningState(); // Reset completely when removed
// Resume visual effects when removed from opening slot
if (Visual != null)
{
Visual.StopPlacementTween(); // Stop any ongoing placement tween
Visual.ResumeEffects();
}
}
}
/// <summary>
/// Reset tap count (useful when starting a new opening sequence)
/// </summary>
public void ResetTapCount()
{
_currentTapCount = 0;
}
/// <summary>
/// Enable or disable tap-to-open functionality at runtime
/// </summary>
public void SetTapToOpenEnabled(bool enabled)
{
canTapToOpen = enabled;
}
}
}