diff --git a/Assets/Scripts/UI/CardSystem/AlbumViewPage.cs b/Assets/Scripts/UI/CardSystem/AlbumViewPage.cs
index 71b2190e..6f7d88c6 100644
--- a/Assets/Scripts/UI/CardSystem/AlbumViewPage.cs
+++ b/Assets/Scripts/UI/CardSystem/AlbumViewPage.cs
@@ -153,6 +153,10 @@ namespace UI.CardSystem
{
if (boosterOpeningPage != null && UIPageController.Instance != null)
{
+ // Pass current booster count to the opening page
+ int boosterCount = CardSystemManager.Instance?.GetBoosterPackCount() ?? 0;
+ boosterOpeningPage.SetAvailableBoosterCount(boosterCount);
+
UIPageController.Instance.PushPage(boosterOpeningPage);
}
}
diff --git a/Assets/Scripts/UI/CardSystem/BoosterOpeningPage.cs b/Assets/Scripts/UI/CardSystem/BoosterOpeningPage.cs
index ba14c0e6..4146f81a 100644
--- a/Assets/Scripts/UI/CardSystem/BoosterOpeningPage.cs
+++ b/Assets/Scripts/UI/CardSystem/BoosterOpeningPage.cs
@@ -1,9 +1,12 @@
-using System.Collections;
+using System.Collections;
using System.Collections.Generic;
+using System.Linq;
using AppleHills.Data.CardSystem;
using Data.CardSystem;
using Pixelplacement;
using UI.Core;
+using UI.CardSystem.DragDrop;
+using UI.DragAndDrop.Core;
using UnityEngine;
using UnityEngine.UI;
@@ -11,7 +14,7 @@ namespace UI.CardSystem
{
///
/// UI page for opening booster packs and displaying the cards received.
- /// Automatically triggers the opening when the page is shown.
+ /// Manages the entire booster opening flow with drag-and-drop interaction.
///
public class BoosterOpeningPage : UIPage
{
@@ -19,13 +22,26 @@ namespace UI.CardSystem
[SerializeField] private CanvasGroup canvasGroup;
[SerializeField] private Button closeButton;
+ [Header("Booster Management")]
+ [SerializeField] private GameObject[] boosterPackInstances; // Booster prefabs/instances
+ [SerializeField] private SlotContainer bottomRightSlots; // Holds waiting boosters
+ [SerializeField] private DraggableSlot centerOpeningSlot; // Where booster goes to open
+
[Header("Card Display")]
[SerializeField] private Transform cardDisplayContainer;
- [SerializeField] private CardDisplay cardDisplayPrefab;
+ [SerializeField] private GameObject flippableCardPrefab; // Placeholder for card backs
+ [SerializeField] private float cardSpacing = 150f;
[Header("Settings")]
[SerializeField] private float cardRevealDelay = 0.5f;
- [SerializeField] private float cardSpacing = 50f;
+ [SerializeField] private float boosterDisappearDuration = 0.5f;
+
+ private int _availableBoosterCount;
+ private BoosterPackDraggable _currentBoosterInCenter;
+ private List _currentRevealedCards = new List();
+ private CardData[] _currentCardData;
+ private int _revealedCardCount;
+ private bool _isProcessingOpening;
private void Awake()
{
@@ -51,6 +67,15 @@ namespace UI.CardSystem
{
closeButton.onClick.RemoveListener(OnCloseButtonClicked);
}
+
+ // Unsubscribe from slot events
+ if (centerOpeningSlot != null)
+ {
+ centerOpeningSlot.OnOccupied -= OnBoosterPlacedInCenter;
+ }
+
+ // Unsubscribe from booster events
+ UnsubscribeFromAllBoosters();
}
private void OnCloseButtonClicked()
@@ -61,6 +86,371 @@ namespace UI.CardSystem
}
}
+ ///
+ /// Set the number of available booster packs before showing the page
+ ///
+ public void SetAvailableBoosterCount(int count)
+ {
+ _availableBoosterCount = count;
+ }
+
+ public override void TransitionIn()
+ {
+ base.TransitionIn();
+ InitializeBoosterDisplay();
+ }
+
+ public override void TransitionOut()
+ {
+ CleanupPage();
+ base.TransitionOut();
+ }
+
+ ///
+ /// Initialize the booster pack display based on available count
+ ///
+ private void InitializeBoosterDisplay()
+ {
+ if (boosterPackInstances == null || boosterPackInstances.Length == 0)
+ {
+ Debug.LogWarning("BoosterOpeningPage: No booster pack instances assigned!");
+ return;
+ }
+
+ // Calculate how many boosters to show (capped by array size)
+ int visibleCount = Mathf.Min(_availableBoosterCount, boosterPackInstances.Length);
+
+ // Show/hide boosters and assign to slots
+ for (int i = 0; i < boosterPackInstances.Length; i++)
+ {
+ if (boosterPackInstances[i] == null) continue;
+
+ bool shouldShow = i < visibleCount;
+ boosterPackInstances[i].SetActive(shouldShow);
+
+ if (shouldShow)
+ {
+ // Get the booster draggable component
+ BoosterPackDraggable booster = boosterPackInstances[i].GetComponent();
+ if (booster != null)
+ {
+ // Reset state
+ booster.ResetTapCount();
+ booster.SetTapToOpenEnabled(false); // Disable tap-to-open until in center
+
+ // Subscribe to events
+ booster.OnReadyToOpen += OnBoosterReadyToOpen;
+
+ // Assign to bottom-right slot if slots available
+ if (bottomRightSlots != null && i < bottomRightSlots.SlotCount)
+ {
+ DraggableSlot slot = bottomRightSlots.GetSlotAtIndex(i);
+ if (slot != null)
+ {
+ booster.AssignToSlot(slot, false);
+ }
+ }
+ }
+ }
+ }
+
+ // Subscribe to center slot events
+ if (centerOpeningSlot != null)
+ {
+ centerOpeningSlot.OnOccupied += OnBoosterPlacedInCenter;
+ }
+ }
+
+ ///
+ /// Handle when a booster is placed in the center opening slot
+ ///
+ private void OnBoosterPlacedInCenter(DraggableObject draggable)
+ {
+ BoosterPackDraggable booster = draggable as BoosterPackDraggable;
+ if (booster == null) return;
+
+ _currentBoosterInCenter = booster;
+
+ // Lock the slot so it can't be dragged out
+ centerOpeningSlot.SetLocked(true);
+
+ // Enable tap-to-open and reset tap count
+ booster.ResetTapCount();
+ booster.SetTapToOpenEnabled(true);
+ }
+
+ ///
+ /// Handle tap-to-place: When player taps a booster in bottom slots, move it to center
+ ///
+ public void OnBoosterTappedInBottomSlot(BoosterPackDraggable booster)
+ {
+ if (_currentBoosterInCenter != null || centerOpeningSlot == null)
+ return; // Center slot already occupied
+
+ // Move booster to center slot
+ booster.AssignToSlot(centerOpeningSlot, true);
+ }
+
+ ///
+ /// Handle when booster is ready to open (after max taps)
+ ///
+ private void OnBoosterReadyToOpen(BoosterPackDraggable booster)
+ {
+ if (_isProcessingOpening) return;
+
+ StartCoroutine(ProcessBoosterOpening(booster));
+ }
+
+ ///
+ /// Process the booster opening sequence
+ ///
+ private IEnumerator ProcessBoosterOpening(BoosterPackDraggable booster)
+ {
+ _isProcessingOpening = true;
+
+ // Call CardSystemManager to open the pack
+ if (CardSystemManager.Instance != null)
+ {
+ List revealedCardsList = CardSystemManager.Instance.OpenBoosterPack();
+ _currentCardData = revealedCardsList.ToArray();
+
+ // Animate booster disappearing
+ yield return StartCoroutine(AnimateBoosterDisappear(booster));
+
+ // Show card backs
+ SpawnCardBacks(_currentCardData.Length);
+
+ // Wait for player to reveal all cards
+ yield return StartCoroutine(WaitForCardReveals());
+
+ // Check if more boosters available
+ _availableBoosterCount--;
+
+ if (_availableBoosterCount > 0)
+ {
+ // Show next booster
+ yield return StartCoroutine(ShowNextBooster());
+ }
+ else
+ {
+ // No more boosters, auto-close page
+ yield return new WaitForSeconds(1f);
+ if (UIPageController.Instance != null)
+ {
+ UIPageController.Instance.PopPage();
+ }
+ }
+ }
+
+ _isProcessingOpening = false;
+ }
+
+ ///
+ /// Animate the booster pack disappearing
+ ///
+ private IEnumerator AnimateBoosterDisappear(BoosterPackDraggable booster)
+ {
+ if (booster == null) yield break;
+
+ // Scale down and fade out
+ Transform boosterTransform = booster.transform;
+
+ Tween.LocalScale(boosterTransform, Vector3.zero, boosterDisappearDuration, 0f, Tween.EaseInBack);
+
+ // Also fade the visual if it has a CanvasGroup
+ CanvasGroup boosterCg = booster.GetComponentInChildren();
+ if (boosterCg != null)
+ {
+ Tween.Value(1f, 0f, (val) => boosterCg.alpha = val, boosterDisappearDuration, 0f);
+ }
+
+ yield return new WaitForSeconds(boosterDisappearDuration);
+
+ // Destroy the booster
+ Destroy(booster.gameObject);
+ _currentBoosterInCenter = null;
+
+ // Unlock center slot
+ centerOpeningSlot.SetLocked(false);
+ }
+
+ ///
+ /// Spawn card back placeholders for revealing
+ ///
+ private void SpawnCardBacks(int count)
+ {
+ if (flippableCardPrefab == null || cardDisplayContainer == null)
+ {
+ Debug.LogWarning("BoosterOpeningPage: Missing card prefab or container!");
+ return;
+ }
+
+ _currentRevealedCards.Clear();
+ _revealedCardCount = 0;
+
+ // Calculate positions
+ float totalWidth = (count - 1) * cardSpacing;
+ float startX = -totalWidth / 2f;
+
+ for (int i = 0; i < count; i++)
+ {
+ GameObject cardObj = Instantiate(flippableCardPrefab, cardDisplayContainer);
+ RectTransform cardRect = cardObj.GetComponent();
+
+ if (cardRect != null)
+ {
+ cardRect.anchoredPosition = new Vector2(startX + (i * cardSpacing), 0);
+ }
+
+ // Add button to handle reveal on click
+ Button cardButton = cardObj.GetComponent