Merge a card refresh (#59)
- **Refactored Card Placement Flow** - Separated card presentation from orchestration logic - Extracted `CornerCardManager` for pending card lifecycle (spawn, shuffle, rebuild) - Extracted `AlbumNavigationService` for book page navigation and zone mapping - Extracted `CardEnlargeController` for backdrop management and card reparenting - Implemented controller pattern (non-MonoBehaviour) for complex logic - Cards now unparent from slots before rebuild to prevent premature destruction - **Improved Corner Card Display** - Fixed cards spawning on top of each other during rebuild - Implemented shuffle-to-front logic (remaining cards occupy slots 0→1→2) - Added smart card selection (prioritizes cards matching current album page) - Pending cards now removed from queue immediately on drag start - Corner cards rebuild after each placement with proper slot reassignment - **Enhanced Album Card Viewing** - Added dramatic scale increase when viewing cards from album slots - Implemented shrink animation when dismissing enlarged cards - Cards transition: `PlacedInSlotState` → `AlbumEnlargedState` → `PlacedInSlotState` - Backdrop shows/hides with card enlarge/shrink cycle - Cards reparent to enlarged container while viewing, return to slot after - **State Machine Improvements** - Added `CardStateNames` constants for type-safe state transitions - Implemented `ICardClickHandler` and `ICardStateDragHandler` interfaces - State transitions now use cached property indices - `BoosterCardContext` separated from `CardContext` for single responsibility - **Code Cleanup** - Identified unused `SlotContainerHelper.cs` (superseded by `CornerCardManager`) - Identified unused `BoosterPackDraggable.canOpenOnDrop` field - Identified unused `AlbumViewPage._previousInputMode` (hardcoded value) - Identified unused `Card.OnPlacedInAlbumSlot` event (no subscribers) Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Co-authored-by: Michal Pikulski <michal@foolhardyhorizons.com> Reviewed-on: #59
This commit is contained in:
674
docs/card_system_guide.md
Normal file
674
docs/card_system_guide.md
Normal file
@@ -0,0 +1,674 @@
|
||||
# Card System Guide
|
||||
|
||||
Complete guide to the Apple Hills card collecting and album system.
|
||||
|
||||
## Table of Contents
|
||||
- [Overview](#overview)
|
||||
- [Quick Start](#quick-start)
|
||||
- [System Architecture](#system-architecture)
|
||||
- [Card Flows](#card-flows)
|
||||
- [Key Components](#key-components)
|
||||
- [Working with Cards in Code](#working-with-cards-in-code)
|
||||
- [Extending the System](#extending-the-system)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Card System manages the player's collectible card journey from booster pack opening to album placement. It consists of:
|
||||
|
||||
- **Booster Opening Flow**: Interactive pack opening with card reveals
|
||||
- **Album Placement Flow**: Drag-and-drop cards into album slots
|
||||
- **State Machine**: Each card progresses through well-defined states
|
||||
- **Album Navigation**: Book-based album with zone tabs
|
||||
- **Notification System**: Visual feedback for new boosters/pending cards
|
||||
|
||||
### Core Concepts
|
||||
|
||||
**CardData**: Runtime data for a single card (definition ID, rarity, zone, image)
|
||||
**CardDefinition**: ScriptableObject template defining card properties
|
||||
**Card States**: Cards transition through states (Idle → Revealed → Dragging → Placed)
|
||||
**Pending Cards**: Cards waiting to be placed in the album (shown in bottom-right corner)
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Opening the Album
|
||||
|
||||
```csharp
|
||||
// From any script
|
||||
if (UIPageController.Instance != null)
|
||||
{
|
||||
UIPageController.Instance.PushPage(albumViewPage);
|
||||
}
|
||||
```
|
||||
|
||||
### Granting Booster Packs
|
||||
|
||||
```csharp
|
||||
// Simple API
|
||||
CardSystemManager.Instance.AddBoosterPack(1);
|
||||
|
||||
// Visual grant with animation (from minigames)
|
||||
MinigameBoosterGiver.Instance.GiveBooster(() => {
|
||||
Debug.Log("Booster granted and animation complete!");
|
||||
});
|
||||
```
|
||||
|
||||
### Opening a Booster Pack (Programmatic)
|
||||
|
||||
```csharp
|
||||
// Returns list of cards in the pack
|
||||
List<CardData> cards = CardSystemManager.Instance.OpenBoosterPack();
|
||||
|
||||
// The cards are automatically added to "pending" state
|
||||
// Player must place them in album manually
|
||||
```
|
||||
|
||||
### Checking Player's Collection
|
||||
|
||||
```csharp
|
||||
var inventory = CardSystemManager.Instance.GetCardInventory();
|
||||
|
||||
// Check if player owns a specific card
|
||||
CardData ownedCard = inventory.GetCard("CardDefID", CardRarity.Legendary);
|
||||
|
||||
// Get all cards in a zone
|
||||
List<CardData> townCards = inventory.GetCardsByZone(CardZone.Town);
|
||||
|
||||
// Check completion percentage
|
||||
float completion = inventory.GetCompletionPercentage();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## System Architecture
|
||||
|
||||
### Component Hierarchy
|
||||
|
||||
```
|
||||
CardSystemManager (Singleton)
|
||||
├── Inventory Management
|
||||
├── Booster Pack Logic
|
||||
└── Pending Card Queue
|
||||
|
||||
AlbumViewPage (UI Page)
|
||||
├── CornerCardManager (Non-Component)
|
||||
│ └── Manages 3 pending cards in corner
|
||||
├── AlbumNavigationService (Non-Component)
|
||||
│ └── Book page flipping & zone navigation
|
||||
└── CardEnlargeController (Non-Component)
|
||||
└── Backdrop & enlarge/shrink animations
|
||||
|
||||
BoosterOpeningPage (UI Page)
|
||||
└── Manages pack opening flow & card reveals
|
||||
|
||||
Card (MonoBehaviour)
|
||||
├── CardContext (shared state)
|
||||
├── CardAnimator (animations)
|
||||
├── CardDisplay (visuals)
|
||||
└── StateMachine (10 possible states)
|
||||
```
|
||||
|
||||
### Non-Component Controllers
|
||||
|
||||
The system uses **Controller** pattern for complex logic without Unity lifecycle overhead:
|
||||
|
||||
- **CornerCardManager**: Spawns/despawns pending cards, smart selection, shuffle logic
|
||||
- **AlbumNavigationService**: Book page navigation, zone mapping
|
||||
- **CardEnlargeController**: Backdrop visibility, card reparenting for enlarge view
|
||||
- **ProgressBarController**: Booster opening progress visualization
|
||||
|
||||
These are instantiated lazily via C# properties:
|
||||
```csharp
|
||||
private CornerCardManager _cornerCardManager;
|
||||
private CornerCardManager CornerCards => _cornerCardManager ??= new CornerCardManager(...);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Card Flows
|
||||
|
||||
### 1. Booster Opening Flow
|
||||
|
||||
```
|
||||
Player opens booster pack
|
||||
↓
|
||||
BoosterOpeningPage spawns cards face-down
|
||||
↓
|
||||
Player clicks a card (IdleState → EnlargedNewState/EnlargedRepeatState)
|
||||
↓
|
||||
Card flips & enlarges, shows NEW or REPEAT badge
|
||||
↓
|
||||
Player clicks to dismiss (→ RevealedState)
|
||||
↓
|
||||
Repeat until all cards revealed
|
||||
↓
|
||||
Cards fly to album icon, added to pending queue
|
||||
↓
|
||||
Page auto-closes (or waits for player)
|
||||
```
|
||||
|
||||
**Key States:**
|
||||
- **IdleState**: Face-down, awaiting click
|
||||
- **EnlargedNewState**: NEW badge (first time collection)
|
||||
- **EnlargedRepeatState**: REPEAT badge (duplicate)
|
||||
- **EnlargedLegendaryRepeatState**: Special legendary repeat state
|
||||
- **RevealedState**: Face-up, dismissed from center
|
||||
|
||||
### 2. Album Placement Flow
|
||||
|
||||
```
|
||||
AlbumViewPage opens
|
||||
↓
|
||||
CornerCardManager spawns up to 3 pending cards (face-down)
|
||||
↓
|
||||
Player drags card (PendingFaceDownState → DraggingRevealedState)
|
||||
↓
|
||||
Card data assigned, flips to reveal, book navigates to correct zone page
|
||||
↓
|
||||
Player drops card on matching AlbumCardSlot
|
||||
↓
|
||||
Card placed (→ PlacedInSlotState), registered with AlbumViewPage
|
||||
↓
|
||||
CornerCardManager rebuilds: shuffles remaining cards, spawns new if available
|
||||
```
|
||||
|
||||
**Key States:**
|
||||
- **PendingFaceDownState**: Face-down in corner, no data assigned yet
|
||||
- **DraggingRevealedState**: Data assigned, flipped, dragging to slot
|
||||
- **PlacedInSlotState**: Locked in album slot
|
||||
- **AlbumEnlargedState**: Clicked from slot, enlarged for viewing
|
||||
|
||||
### 3. Album Card Viewing
|
||||
|
||||
```
|
||||
Player clicks placed card in album slot
|
||||
↓
|
||||
Card enlarges (PlacedInSlotState → AlbumEnlargedState)
|
||||
↓
|
||||
Backdrop shown, card reparented to enlarged container
|
||||
↓
|
||||
Card animates to center with dramatic scale increase
|
||||
↓
|
||||
Player clicks card or backdrop to dismiss
|
||||
↓
|
||||
Card shrinks & animates back to slot (→ PlacedInSlotState)
|
||||
↓
|
||||
Backdrop hidden, card reparented back to slot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Components
|
||||
|
||||
### CardSystemManager
|
||||
|
||||
**Singleton** managing all card data and inventory.
|
||||
|
||||
```csharp
|
||||
// Access
|
||||
CardSystemManager.Instance
|
||||
|
||||
// Key Methods
|
||||
.AddBoosterPack(int count) // Grant booster packs
|
||||
.OpenBoosterPack() // Open a pack, returns CardData[]
|
||||
.GetPendingRevealCards() // Get cards waiting for album placement
|
||||
.GetCardInventory() // Access player's collection
|
||||
.AddCardToInventory(CardData) // Add card to collection
|
||||
.RemoveFromPending(CardData) // Remove from pending queue
|
||||
|
||||
// Events
|
||||
.OnBoosterCountChanged(int newCount)
|
||||
.OnPendingCardAdded(CardData)
|
||||
.OnPendingCardRemoved(CardData)
|
||||
```
|
||||
|
||||
### AlbumViewPage
|
||||
|
||||
**UI Page** for viewing and managing the album.
|
||||
|
||||
```csharp
|
||||
// Setup in scene:
|
||||
// - Assign book reference (BookPro component)
|
||||
// - Assign zone tab container
|
||||
// - Assign card prefab for spawning
|
||||
// - Assign backdrop & enlarged container for card viewing
|
||||
// - Link to BoosterOpeningPage
|
||||
|
||||
// Query Methods (used by Card states)
|
||||
public CardData GetCardForPendingSlot() // Smart card selection
|
||||
public AlbumCardSlot GetTargetSlotForCard(CardData) // Find destination slot
|
||||
public void NavigateToCardPage(CardData, Action) // Flip to correct page
|
||||
public void NotifyCardPlaced(Card) // Cleanup after placement
|
||||
|
||||
// Public Properties
|
||||
public bool IsPageFlipping // For state timing checks
|
||||
```
|
||||
|
||||
### BoosterOpeningPage
|
||||
|
||||
**UI Page** for opening booster packs.
|
||||
|
||||
```csharp
|
||||
// Setup in scene:
|
||||
// - Assign booster pack prefab
|
||||
// - Assign corner slots for waiting boosters (max 3)
|
||||
// - Assign center slot for opening
|
||||
// - Assign card display container
|
||||
// - Assign card prefab
|
||||
// - Assign album icon (dismiss button & tween target)
|
||||
|
||||
// Call before showing:
|
||||
.SetAvailableBoosterCount(int count) // How many boosters player has
|
||||
|
||||
// Flow automatically managed by page
|
||||
```
|
||||
|
||||
### Card States
|
||||
|
||||
Each card uses **AppleMachine** state machine with these states:
|
||||
|
||||
| State | Purpose | Entry Trigger |
|
||||
|-------|---------|---------------|
|
||||
| **IdleState** | Face-down in booster opening | Card spawned for booster reveal |
|
||||
| **EnlargedNewState** | Enlarged with NEW badge | Clicked first-time card |
|
||||
| **EnlargedRepeatState** | Enlarged with REPEAT badge | Clicked duplicate |
|
||||
| **EnlargedLegendaryRepeatState** | Legendary repeat variant | Clicked legendary duplicate |
|
||||
| **RevealedState** | Face-up, dismissed | Dismissed from enlarged state |
|
||||
| **PendingFaceDownState** | Face-down in corner | Spawned in album corner |
|
||||
| **DraggingRevealedState** | Face-up while dragging | Dragged from corner |
|
||||
| **PlacedInSlotState** | Locked in album slot | Dropped on correct slot |
|
||||
| **AlbumEnlargedState** | Enlarged from album | Clicked while in slot |
|
||||
| **DraggingState** | Generic drag state | *(unused in current flow)* |
|
||||
|
||||
### Card Context & Components
|
||||
|
||||
Every card has:
|
||||
- **CardContext**: Shared state, component references, events
|
||||
- **CardAnimator**: Centralized animation methods
|
||||
- **CardDisplay**: Visual rendering (image, frame, overlay, rarity/zone styling)
|
||||
- **AppleMachine**: State machine controller
|
||||
|
||||
```csharp
|
||||
// Accessing card components
|
||||
var card = GetComponent<Card>();
|
||||
card.Context.CardData // CardData
|
||||
card.Context.Animator // CardAnimator
|
||||
card.Context.CardDisplay // CardDisplay
|
||||
card.Context.StateMachine // AppleMachine
|
||||
card.Context.AlbumViewPage // Injected page reference
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Working with Cards in Code
|
||||
|
||||
### Spawning a Card for Booster Opening
|
||||
|
||||
```csharp
|
||||
GameObject cardObj = Instantiate(cardPrefab, containerTransform);
|
||||
var card = cardObj.GetComponent<Card>();
|
||||
var context = cardObj.GetComponent<CardContext>();
|
||||
|
||||
// Setup card data
|
||||
context.SetupCard(cardData);
|
||||
|
||||
// Start in IdleState for booster reveal
|
||||
card.SetupForBoosterReveal(cardData, isNew); // isNew unused, states query inventory
|
||||
|
||||
// Subscribe to reveal complete event
|
||||
context.BoosterContext.OnRevealFlowComplete += () => {
|
||||
Debug.Log("Card reveal finished!");
|
||||
};
|
||||
```
|
||||
|
||||
### Spawning a Card for Album Corner
|
||||
|
||||
```csharp
|
||||
GameObject cardObj = Instantiate(cardPrefab, slotTransform);
|
||||
var card = cardObj.GetComponent<Card>();
|
||||
|
||||
// Assign to slot FIRST
|
||||
card.AssignToSlot(slot, animateMove: false);
|
||||
|
||||
// Inject AlbumViewPage dependency
|
||||
card.Context.SetAlbumViewPage(albumViewPage);
|
||||
|
||||
// Setup for pending state (no data yet)
|
||||
card.SetupForAlbumPending(); // Starts in PendingFaceDownState
|
||||
```
|
||||
|
||||
### Spawning a Card Already in Album Slot
|
||||
|
||||
```csharp
|
||||
GameObject cardObj = Instantiate(cardPrefab, slotTransform);
|
||||
var card = cardObj.GetComponent<Card>();
|
||||
|
||||
// Setup for album slot (already owned)
|
||||
card.SetupForAlbumSlot(cardData, albumCardSlot); // Starts in PlacedInSlotState
|
||||
|
||||
// Register for enlarge/shrink functionality
|
||||
albumViewPage.RegisterCardInAlbum(card);
|
||||
```
|
||||
|
||||
### Transitioning Card States Manually
|
||||
|
||||
```csharp
|
||||
// Get card component
|
||||
var card = GetComponent<Card>();
|
||||
|
||||
// Change state
|
||||
card.ChangeState(CardStateNames.Revealed);
|
||||
|
||||
// Check current state
|
||||
string currentState = card.GetCurrentStateName();
|
||||
if (currentState == CardStateNames.PlacedInSlot)
|
||||
{
|
||||
Debug.Log("Card is placed in album!");
|
||||
}
|
||||
|
||||
// Get specific state component
|
||||
var enlargedState = card.GetStateComponent<CardAlbumEnlargedState>(
|
||||
CardStateNames.AlbumEnlarged
|
||||
);
|
||||
if (enlargedState != null)
|
||||
{
|
||||
// Access state-specific methods/properties
|
||||
}
|
||||
```
|
||||
|
||||
### Subscribing to Card Events
|
||||
|
||||
```csharp
|
||||
var context = card.Context;
|
||||
|
||||
// Drag events
|
||||
context.OnDragStarted += (ctx) => Debug.Log("Drag started!");
|
||||
context.OnDragEnded += (ctx) => Debug.Log("Drag ended!");
|
||||
|
||||
// Click events (routed through CardDisplay)
|
||||
context.CardDisplay.OnCardClicked += (display) => Debug.Log("Card clicked!");
|
||||
|
||||
// Booster reveal events
|
||||
context.BoosterContext.OnRevealFlowComplete += () => {
|
||||
Debug.Log("Reveal complete!");
|
||||
CardSystemManager.Instance.AddCardToInventory(context.CardData);
|
||||
};
|
||||
|
||||
// State machine events (if needed)
|
||||
context.StateMachine.OnStateChange += (newState) => Debug.Log($"State: {newState.name}");
|
||||
```
|
||||
|
||||
### Custom Animations
|
||||
|
||||
```csharp
|
||||
var animator = card.Animator;
|
||||
|
||||
// Built-in animations
|
||||
animator.PopIn(duration: 0.5f, onComplete: () => Debug.Log("Popped in!"));
|
||||
animator.PopOut(duration: 0.3f);
|
||||
animator.PlayEnlarge(targetScale: 2.5f);
|
||||
animator.PlayShrink(targetScale: Vector3.one);
|
||||
|
||||
// Combine animations
|
||||
animator.AnimateLocalPosition(Vector3.zero, duration: 0.5f);
|
||||
animator.AnimateScale(Vector3.one * 1.5f, duration: 0.3f);
|
||||
|
||||
// Flip animation
|
||||
Transform cardBack = card.transform.Find("CardBack");
|
||||
Transform cardFront = card.transform.Find("CardDisplay");
|
||||
animator.PlayFlip(cardBack, cardFront, duration: 0.6f, onComplete: () => {
|
||||
Debug.Log("Flip complete!");
|
||||
});
|
||||
animator.PlayFlipScalePunch(punchScale: 1.1f);
|
||||
|
||||
// Hover effects
|
||||
Vector2 originalPos = animator.GetAnchoredPosition();
|
||||
animator.HoverEnter(liftAmount: 20f, scaleMultiplier: 1.05f);
|
||||
// ... later
|
||||
animator.HoverExit(originalPos);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Extending the System
|
||||
|
||||
### Adding a New Card State
|
||||
|
||||
1. **Create State Script** in `StateMachine/States/`
|
||||
```csharp
|
||||
using Core.SaveLoad;
|
||||
using UI.CardSystem.StateMachine;
|
||||
|
||||
public class MyNewCardState : AppleState, ICardClickHandler
|
||||
{
|
||||
private CardContext _context;
|
||||
|
||||
public override void EnterState()
|
||||
{
|
||||
_context = GetComponentInParent<CardContext>();
|
||||
// Setup animations, visuals, etc.
|
||||
}
|
||||
|
||||
public void OnCardClicked(CardContext context)
|
||||
{
|
||||
// Handle click behavior
|
||||
}
|
||||
|
||||
public override void ExitState()
|
||||
{
|
||||
// Cleanup
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Add State Name** to `CardStateNames.cs`
|
||||
```csharp
|
||||
public const string MyNewState = "MyNewCardState";
|
||||
```
|
||||
|
||||
3. **Add GameObject** as child of Card prefab's AppleMachine with your state component attached
|
||||
|
||||
4. **Transition to State**
|
||||
```csharp
|
||||
card.ChangeState(CardStateNames.MyNewState);
|
||||
```
|
||||
|
||||
### Creating a Custom Card Visual Effect
|
||||
|
||||
```csharp
|
||||
public class MyCardEffect : MonoBehaviour
|
||||
{
|
||||
private CardContext _context;
|
||||
|
||||
void Start()
|
||||
{
|
||||
_context = GetComponentInParent<CardContext>();
|
||||
|
||||
// Subscribe to state changes
|
||||
_context.StateMachine.OnStateChange += OnStateChanged;
|
||||
}
|
||||
|
||||
void OnStateChanged(AppleState newState)
|
||||
{
|
||||
if (newState.name == CardStateNames.EnlargedNew)
|
||||
{
|
||||
// Play custom effect
|
||||
PlaySparkleEffect();
|
||||
}
|
||||
}
|
||||
|
||||
void PlaySparkleEffect()
|
||||
{
|
||||
// Your custom effect logic
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Adding Custom Card Slots
|
||||
|
||||
```csharp
|
||||
public class MyCustomCardSlot : AlbumCardSlot
|
||||
{
|
||||
protected override void OnCardPlaced(Card card)
|
||||
{
|
||||
base.OnCardPlaced(card);
|
||||
|
||||
// Custom logic when card placed
|
||||
PlaySpecialEffect();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Cards Not Showing in Corner
|
||||
|
||||
**Check:**
|
||||
1. AlbumViewPage has `cardPrefab` assigned
|
||||
2. AlbumViewPage has `bottomRightSlots` assigned (SlotContainer with 3 slots)
|
||||
3. CardSystemManager has pending cards: `GetPendingRevealCards().Count > 0`
|
||||
4. Page is in album proper (not menu page): Check with `IsInAlbumProper()`
|
||||
|
||||
**Debug:**
|
||||
```csharp
|
||||
Debug.Log($"Pending cards: {CardSystemManager.Instance.GetPendingRevealCards().Count}");
|
||||
Debug.Log($"Is in album: {albumViewPage.IsInAlbumProper()}");
|
||||
```
|
||||
|
||||
### Cards Spawning on Top of Each Other
|
||||
|
||||
**Cause:** Corner slots not properly configured with `SlotIndex` property
|
||||
|
||||
**Fix:**
|
||||
- Ensure each slot has unique `SlotIndex` (0, 1, 2)
|
||||
- Verify in inspector: Select each slot → Check `SlotIndex` field
|
||||
|
||||
### Card Won't Flip
|
||||
|
||||
**Check:**
|
||||
1. Card has `CardBack` child GameObject
|
||||
2. Card has `CardDisplay` child GameObject
|
||||
3. Both have proper hierarchy: `Card → CardBack`, `Card → CardDisplay`
|
||||
4. State transitions are correct
|
||||
|
||||
**Debug:**
|
||||
```csharp
|
||||
var cardBack = card.transform.Find("CardBack");
|
||||
var cardDisplay = card.transform.Find("CardDisplay");
|
||||
Debug.Log($"Back found: {cardBack != null}, Display found: {cardDisplay != null}");
|
||||
Debug.Log($"Current state: {card.GetCurrentStateName()}");
|
||||
```
|
||||
|
||||
### Book Won't Flip to Correct Page
|
||||
|
||||
**Check:**
|
||||
1. BookTabButton components configured with correct `zone` and `targetPage`
|
||||
2. AlbumViewPage has `tabContainer` assigned
|
||||
3. BookPro component reference assigned on AlbumViewPage
|
||||
|
||||
**Debug:**
|
||||
```csharp
|
||||
// In AlbumViewPage
|
||||
foreach (var tab in _zoneTabs)
|
||||
{
|
||||
Debug.Log($"Tab: {tab.Zone} → Page {tab.TargetPage}");
|
||||
}
|
||||
```
|
||||
|
||||
### Cards Not Enlarging When Clicked in Album
|
||||
|
||||
**Check:**
|
||||
1. Card is in `PlacedInSlotState`
|
||||
2. AlbumViewPage has `cardEnlargedBackdrop` and `cardEnlargedContainer` assigned
|
||||
3. Card was registered: `albumViewPage.RegisterCardInAlbum(card)`
|
||||
|
||||
**Debug:**
|
||||
```csharp
|
||||
var enlargedState = card.GetStateComponent<CardAlbumEnlargedState>(CardStateNames.AlbumEnlarged);
|
||||
Debug.Log($"Enlarged state found: {enlargedState != null}");
|
||||
Debug.Log($"Current state: {card.GetCurrentStateName()}");
|
||||
```
|
||||
|
||||
### Memory Leaks / Cards Not Destroying
|
||||
|
||||
**Cause:** Event subscriptions not cleaned up
|
||||
|
||||
**Fix Pattern:**
|
||||
```csharp
|
||||
void OnEnable()
|
||||
{
|
||||
card.Context.OnDragStarted += HandleDrag;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (card != null && card.Context != null)
|
||||
{
|
||||
card.Context.OnDragStarted -= HandleDrag;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Booster Packs Not Appearing
|
||||
|
||||
**Check:**
|
||||
1. BoosterOpeningPage has `boosterPackPrefab` assigned
|
||||
2. BoosterOpeningPage has `bottomRightSlots` assigned
|
||||
3. Called `SetAvailableBoosterCount()` before showing page
|
||||
|
||||
**Debug:**
|
||||
```csharp
|
||||
Debug.Log($"Booster count: {CardSystemManager.Instance.GetBoosterPackCount()}");
|
||||
Debug.Log($"Booster prefab: {boosterOpeningPage.boosterPackPrefab != null}");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State Diagram
|
||||
|
||||
```
|
||||
BOOSTER OPENING FLOW:
|
||||
IdleState ──click──> EnlargedNewState ──click──> RevealedState
|
||||
└──> EnlargedRepeatState ──┘
|
||||
└──> EnlargedLegendaryRepeatState ──┘
|
||||
|
||||
ALBUM PLACEMENT FLOW:
|
||||
PendingFaceDownState ──drag──> DraggingRevealedState ──drop on slot──> PlacedInSlotState
|
||||
│
|
||||
click
|
||||
│
|
||||
↓
|
||||
AlbumEnlargedState
|
||||
│
|
||||
click
|
||||
│
|
||||
↓
|
||||
PlacedInSlotState
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- **Code Location**: `Assets/Scripts/UI/CardSystem/`
|
||||
- **Card Prefabs**: `Assets/Prefabs/UI/Cards/`
|
||||
- **Card Definitions**: `Assets/Data/CardSystem/Definitions/`
|
||||
- **Album Scene**: `Assets/Scenes/Album.unity`
|
||||
|
||||
**Related Systems:**
|
||||
- [UIPageController Documentation](ui_page_navigation.md) - UI page stack navigation
|
||||
- [DragAndDrop System](../Scripts/UI/DragAndDrop/Core/) - Base drag/drop framework
|
||||
- [Settings System](settings_readme.md) - Card system configuration
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** November 18, 2025
|
||||
**Version:** 1.0
|
||||
**Contributors:** Development Team
|
||||
|
||||
Reference in New Issue
Block a user