Working drag, tap, open sequence, looking pretty OK

This commit is contained in:
Michal Pikulski
2025-11-06 19:31:33 +01:00
parent 1b1ea65744
commit 774f27410a
5 changed files with 239 additions and 463 deletions

View File

@@ -25,8 +25,8 @@ namespace UI.CardSystem
[SerializeField] private Button closeButton;
[Header("Booster Management")]
[SerializeField] private GameObject[] boosterPackInstances; // Booster prefabs/instances
[SerializeField] private SlotContainer bottomRightSlots; // Holds waiting boosters
[SerializeField] private GameObject boosterPackPrefab; // Prefab to instantiate new boosters
[SerializeField] private SlotContainer bottomRightSlots; // Holds waiting boosters (max 3)
[SerializeField] private DraggableSlot centerOpeningSlot; // Where booster goes to open
[Header("Card Display")]
@@ -41,10 +41,12 @@ namespace UI.CardSystem
private int _availableBoosterCount;
private BoosterPackDraggable _currentBoosterInCenter;
private List<BoosterPackDraggable> _activeBoostersInSlots = new List<BoosterPackDraggable>();
private List<GameObject> _currentRevealedCards = new List<GameObject>();
private CardData[] _currentCardData;
private int _revealedCardCount;
private bool _isProcessingOpening;
private const int MAX_VISIBLE_BOOSTERS = 3;
private void Awake()
{
@@ -75,6 +77,7 @@ namespace UI.CardSystem
if (centerOpeningSlot != null)
{
centerOpeningSlot.OnOccupied -= OnBoosterPlacedInCenter;
centerOpeningSlot.OnVacated -= OnBoosterRemovedFromCenter;
}
// Unsubscribe from booster events
@@ -116,71 +119,38 @@ namespace UI.CardSystem
{
Debug.Log($"[BoosterOpeningPage] InitializeBoosterDisplay called with {_availableBoosterCount} boosters available");
if (boosterPackInstances == null || boosterPackInstances.Length == 0)
if (boosterPackPrefab == null)
{
Debug.LogWarning("BoosterOpeningPage: No booster pack instances assigned!");
Debug.LogWarning("BoosterOpeningPage: No booster pack prefab assigned!");
return;
}
// Calculate how many boosters to show (capped by array size)
int visibleCount = Mathf.Min(_availableBoosterCount, boosterPackInstances.Length);
Debug.Log($"[BoosterOpeningPage] Will show {visibleCount} boosters out of {boosterPackInstances.Length} instances");
// Show/hide boosters and assign to slots
for (int i = 0; i < boosterPackInstances.Length; i++)
if (bottomRightSlots == null || bottomRightSlots.SlotCount == 0)
{
if (boosterPackInstances[i] == null) continue;
bool shouldShow = i < visibleCount;
Debug.Log($"[BoosterOpeningPage] Booster {i} ({boosterPackInstances[i].name}): shouldShow={shouldShow}, position={boosterPackInstances[i].transform.position}");
boosterPackInstances[i].SetActive(shouldShow);
if (shouldShow)
{
// Get the booster draggable component
BoosterPackDraggable booster = boosterPackInstances[i].GetComponent<BoosterPackDraggable>();
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)
{
Debug.Log($"[BoosterOpeningPage] Assigning booster {i} to slot {slot.name} at {slot.transform.position}");
booster.AssignToSlot(slot, false);
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] Slot {i} is null in bottomRightSlots!");
}
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] No slot available for booster {i}. bottomRightSlots={bottomRightSlots}, SlotCount={bottomRightSlots?.SlotCount}");
}
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] Booster {i} has no BoosterPackDraggable component!");
}
}
Debug.LogWarning("BoosterOpeningPage: No slots available!");
return;
}
// Clear any existing boosters
_activeBoostersInSlots.Clear();
// Calculate how many boosters to show (max 3, or available count, whichever is lower)
int visibleCount = Mathf.Min(_availableBoosterCount, MAX_VISIBLE_BOOSTERS);
Debug.Log($"[BoosterOpeningPage] Will spawn {visibleCount} boosters");
// Spawn boosters and assign to slots
for (int i = 0; i < visibleCount; i++)
{
SpawnBoosterInSlot(i);
}
// Subscribe to center slot events
if (centerOpeningSlot != null)
{
centerOpeningSlot.OnOccupied += OnBoosterPlacedInCenter;
Debug.Log($"[BoosterOpeningPage] Subscribed to center slot {centerOpeningSlot.name} at {centerOpeningSlot.transform.position}");
centerOpeningSlot.OnVacated += OnBoosterRemovedFromCenter;
Debug.Log($"[BoosterOpeningPage] Subscribed to center slot events");
}
else
{
@@ -188,6 +158,137 @@ namespace UI.CardSystem
}
}
/// <summary>
/// Spawn a new booster and place it in the specified slot index
/// </summary>
private void SpawnBoosterInSlot(int slotIndex)
{
if (slotIndex >= bottomRightSlots.SlotCount)
{
Debug.LogWarning($"[BoosterOpeningPage] Slot index {slotIndex} out of range!");
return;
}
DraggableSlot slot = bottomRightSlots.GetSlotAtIndex(slotIndex);
if (slot == null)
{
Debug.LogWarning($"[BoosterOpeningPage] Slot {slotIndex} is null!");
return;
}
// Instantiate booster
GameObject boosterObj = Instantiate(boosterPackPrefab, slot.transform);
BoosterPackDraggable booster = boosterObj.GetComponent<BoosterPackDraggable>();
if (booster != null)
{
// Reset state
booster.ResetTapCount();
booster.SetTapToOpenEnabled(false);
// Subscribe to events
booster.OnReadyToOpen += OnBoosterReadyToOpen;
// Assign to slot with animation
booster.AssignToSlot(slot, true);
// Track it
_activeBoostersInSlots.Add(booster);
Debug.Log($"[BoosterOpeningPage] Spawned booster in slot {slotIndex}");
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] Spawned booster has no BoosterPackDraggable component!");
Destroy(boosterObj);
}
}
/// <summary>
/// Remove and destroy the booster from the specified slot
/// </summary>
private void RemoveBoosterFromSlot(int slotIndex)
{
if (slotIndex >= _activeBoostersInSlots.Count)
return;
BoosterPackDraggable booster = _activeBoostersInSlots[slotIndex];
if (booster != null)
{
// Unsubscribe from events
booster.OnReadyToOpen -= OnBoosterReadyToOpen;
// Animate out and destroy
Transform boosterTransform = booster.transform;
Tween.LocalScale(boosterTransform, Vector3.zero, 0.3f, 0f, Tween.EaseInBack,
completeCallback: () =>
{
if (booster != null && booster.gameObject != null)
{
Destroy(booster.gameObject);
}
});
// Remove from slot
if (booster.CurrentSlot != null)
{
booster.CurrentSlot.Vacate();
}
Debug.Log($"[BoosterOpeningPage] Removed booster from slot {slotIndex}");
}
_activeBoostersInSlots.RemoveAt(slotIndex);
}
/// <summary>
/// Update visible boosters based on available count
/// </summary>
private void UpdateVisibleBoosters()
{
int targetCount = Mathf.Min(_availableBoosterCount, MAX_VISIBLE_BOOSTERS);
// Remove excess boosters (from the end)
while (_activeBoostersInSlots.Count > targetCount)
{
int lastIndex = _activeBoostersInSlots.Count - 1;
RemoveBoosterFromSlot(lastIndex);
}
Debug.Log($"[BoosterOpeningPage] Updated visible boosters: {_activeBoostersInSlots.Count}/{targetCount}");
}
/// <summary>
/// Try to spawn a new booster to maintain up to 3 visible
/// Pass decrementCount=true when called after placing a booster in center slot
/// (accounts for the booster that will be consumed)
/// </summary>
private void TrySpawnNewBooster(bool decrementCount = false)
{
// Can we spawn more boosters?
if (_activeBoostersInSlots.Count >= MAX_VISIBLE_BOOSTERS)
return; // Already at max
// Use decremented count if this is called after placing in center
// (the booster in center will be consumed, so we check against count - 1)
int effectiveCount = decrementCount ? _availableBoosterCount - 1 : _availableBoosterCount;
if (_activeBoostersInSlots.Count >= effectiveCount)
return; // No more boosters available
// Find first available slot
for (int i = 0; i < MAX_VISIBLE_BOOSTERS; i++)
{
DraggableSlot slot = bottomRightSlots.GetSlotAtIndex(i);
if (slot != null && !slot.IsOccupied)
{
SpawnBoosterInSlot(i);
Debug.Log($"[BoosterOpeningPage] Spawned new booster in slot {i}");
break;
}
}
}
/// <summary>
/// Handle when a booster is placed in the center opening slot
/// </summary>
@@ -198,17 +299,46 @@ namespace UI.CardSystem
_currentBoosterInCenter = booster;
// Lock the slot so it can't be dragged out
centerOpeningSlot.SetLocked(true);
// Remove from active slots list
_activeBoostersInSlots.Remove(booster);
// Lock the slot so it can't be dragged out
Debug.Log($"[BoosterOpeningPage] Locking center slot. IsLocked before: {centerOpeningSlot.IsLocked}");
centerOpeningSlot.SetLocked(true);
Debug.Log($"[BoosterOpeningPage] IsLocked after: {centerOpeningSlot.IsLocked}");
// Configure booster for opening (disables drag, enables tapping, resets tap count)
Debug.Log($"[BoosterOpeningPage] Calling SetInOpeningSlot(true) on booster");
booster.SetInOpeningSlot(true);
// Subscribe to tap events for visual feedback
booster.OnTapped += OnBoosterTapped;
booster.OnReadyToOpen += OnBoosterReadyToOpen;
Debug.Log($"[BoosterOpeningPage] Booster placed in center, ready for {booster.CurrentTapCount} taps");
// Try to spawn a new booster to maintain 3 visible
// Use decrementCount=true because this booster will be consumed
TrySpawnNewBooster(decrementCount: true);
Debug.Log($"[BoosterOpeningPage] Booster placed in center, ready for taps. Active boosters in slots: {_activeBoostersInSlots.Count}");
}
/// <summary>
/// Handle when a booster is removed from the center opening slot
/// </summary>
private void OnBoosterRemovedFromCenter(DraggableObject draggable)
{
BoosterPackDraggable booster = draggable as BoosterPackDraggable;
if (booster == null) return;
// If it's being removed back to a corner slot, add it back to tracking
if (booster.CurrentSlot != null && bottomRightSlots.HasSlot(booster.CurrentSlot))
{
_activeBoostersInSlots.Add(booster);
booster.SetInOpeningSlot(false);
}
_currentBoosterInCenter = null;
Debug.Log($"[BoosterOpeningPage] Booster removed from center");
}
private void OnBoosterTapped(BoosterPackDraggable booster, int currentTaps, int maxTaps)
@@ -275,21 +405,19 @@ namespace UI.CardSystem
// Animate booster disappearing
yield return StartCoroutine(AnimateBoosterDisappear(booster));
// Decrement available count
_availableBoosterCount--;
// Update visible boosters (remove from end if we drop below thresholds)
UpdateVisibleBoosters();
// 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
if (_availableBoosterCount <= 0)
{
// No more boosters, auto-close page
yield return new WaitForSeconds(1f);
@@ -327,7 +455,7 @@ namespace UI.CardSystem
// Destroy the booster
Destroy(booster.gameObject);
_currentBoosterInCenter = null;
// Unlock center slot
centerOpeningSlot.SetLocked(false);
}
@@ -437,40 +565,6 @@ namespace UI.CardSystem
yield return new WaitForSeconds(0.5f);
}
/// <summary>
/// Show the next booster pack
/// </summary>
private IEnumerator ShowNextBooster()
{
// Find the next inactive booster and activate it
for (int i = 0; i < boosterPackInstances.Length; i++)
{
if (boosterPackInstances[i] != null && !boosterPackInstances[i].activeSelf)
{
boosterPackInstances[i].SetActive(true);
BoosterPackDraggable booster = boosterPackInstances[i].GetComponent<BoosterPackDraggable>();
if (booster != null)
{
booster.ResetTapCount();
booster.SetTapToOpenEnabled(false);
booster.OnReadyToOpen += OnBoosterReadyToOpen;
// Assign to first available slot
DraggableSlot slot = bottomRightSlots?.GetAvailableSlots().FirstOrDefault();
if (slot != null)
{
booster.AssignToSlot(slot, true);
}
}
break;
}
}
yield return null;
}
/// <summary>
/// Clean up the page when hidden
/// </summary>
@@ -478,6 +572,14 @@ namespace UI.CardSystem
{
UnsubscribeFromAllBoosters();
// Destroy all active boosters
foreach (var booster in _activeBoostersInSlots.ToList())
{
if (booster != null && booster.gameObject != null)
Destroy(booster.gameObject);
}
_activeBoostersInSlots.Clear();
// Clear any remaining cards
foreach (GameObject card in _currentRevealedCards)
{
@@ -495,18 +597,22 @@ namespace UI.CardSystem
/// </summary>
private void UnsubscribeFromAllBoosters()
{
if (boosterPackInstances == null) return;
foreach (GameObject boosterObj in boosterPackInstances)
// Unsubscribe from active boosters in slots
foreach (var booster in _activeBoostersInSlots)
{
if (boosterObj == null) continue;
BoosterPackDraggable booster = boosterObj.GetComponent<BoosterPackDraggable>();
if (booster != null)
{
booster.OnReadyToOpen -= OnBoosterReadyToOpen;
booster.OnTapped -= OnBoosterTapped;
}
}
// Unsubscribe from center booster
if (_currentBoosterInCenter != null)
{
_currentBoosterInCenter.OnReadyToOpen -= OnBoosterReadyToOpen;
_currentBoosterInCenter.OnTapped -= OnBoosterTapped;
}
}
protected override void DoTransitionIn(System.Action onComplete)

View File

@@ -246,7 +246,13 @@ namespace UI.CardSystem.DragDrop
protected override void HandleDragEnded(DraggableObject draggable)
{
// Don't call base if effects are suppressed (in opening slot)
// 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;

View File

@@ -445,6 +445,11 @@ namespace UI.DragAndDrop.Core
if (RectTransform != null)
{
// Pop-in animation: start slightly scaled down, then bounce to normal
Vector3 startScale = transform.localScale * 0.8f;
transform.localScale = startScale;
Tween.LocalScale(transform, Vector3.one, snapDuration, 0f, Tween.EaseOutBack);
Tween.LocalPosition(RectTransform, targetLocalPos, snapDuration, 0f, Tween.EaseOutBack);
Tween.LocalRotation(transform, Quaternion.identity, snapDuration, 0f, Tween.EaseOutBack);
}

View File

@@ -153,6 +153,14 @@ namespace UI.DragAndDrop.Core
return _slots[index];
}
/// <summary>
/// Check if this container contains the specified slot
/// </summary>
public bool HasSlot(DraggableSlot slot)
{
return _slots.Contains(slot);
}
/// <summary>
/// Update the layout of all slots based on layout type
/// </summary>