2025-11-12 11:58:01 +01:00
|
|
|
|
# Card State Machine Implementation Summary
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
|
|
|
|
|
## Architecture Overview
|
|
|
|
|
|
|
|
|
|
|
|
**Isolated State Pattern** using Pixelplacement StateMachine:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
Card (RectTransform - primary animation target)
|
2025-11-12 11:58:01 +01:00
|
|
|
|
├─ CardDisplay (always visible - shows card front)
|
|
|
|
|
|
├─ CardContext (shared references + events)
|
2025-11-11 21:03:05 +01:00
|
|
|
|
├─ CardAnimator (reusable animations)
|
|
|
|
|
|
└─ CardStateMachine (AppleMachine)
|
|
|
|
|
|
├─ IdleState/
|
2025-11-12 11:58:01 +01:00
|
|
|
|
│ └─ CardBackVisual ← State owns this
|
2025-11-11 21:03:05 +01:00
|
|
|
|
├─ FlippingState/
|
|
|
|
|
|
│ └─ CardBackVisual ← State owns this
|
2025-11-12 11:58:01 +01:00
|
|
|
|
├─ RevealedState/
|
|
|
|
|
|
│ ├─ NewCardIdleBadge ← State owns this
|
|
|
|
|
|
│ └─ RepeatCardIdleBadge ← State owns this
|
2025-11-11 21:03:05 +01:00
|
|
|
|
├─ EnlargedNewState/
|
|
|
|
|
|
│ └─ NewCardBadge ← State owns this
|
2025-11-12 11:58:01 +01:00
|
|
|
|
├─ EnlargedRepeatState/
|
|
|
|
|
|
│ ├─ RepeatText ← State owns this
|
|
|
|
|
|
│ └─ ProgressBarContainer/
|
|
|
|
|
|
│ └─ ProgressBarUI (prefab with ProgressBarController)
|
|
|
|
|
|
├─ DraggingState/ (no child visuals)
|
|
|
|
|
|
├─ PlacedInSlotState/ (no child visuals)
|
|
|
|
|
|
└─ AlbumEnlargedState/ (no child visuals)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## State Flow Diagrams
|
|
|
|
|
|
|
|
|
|
|
|
### **Booster Opening Flow:**
|
|
|
|
|
|
↓ [player clicks]
|
|
|
|
|
|
2. FlippingState (flip animation + scale punch)
|
|
|
|
|
|
1. IdleState (card back in assigned slot, hover enabled)
|
|
|
|
|
|
↓ [player clicks - flip animation plays within IdleState]
|
|
|
|
|
|
3a. IF NEW CARD:
|
|
|
|
|
|
↓ [determine path based on card status]
|
|
|
|
|
|
|
|
|
|
|
|
2a. IF NEW CARD:
|
|
|
|
|
|
3b. IF LEGENDARY REPEAT:
|
|
|
|
|
|
→ [tap] → Fires OnCardDismissed
|
|
|
|
|
|
→ Shrink → RevealedState
|
|
|
|
|
|
3c. IF REPEAT (won't upgrade, e.g., 2/5):
|
|
|
|
|
|
2b. IF LEGENDARY REPEAT:
|
|
|
|
|
|
→ Skip enlarge → RevealedState (can't upgrade)
|
|
|
|
|
|
|
|
|
|
|
|
2c. IF REPEAT (won't upgrade, e.g., 2/5):
|
|
|
|
|
|
→ EnlargedRepeatState
|
|
|
|
|
|
3d. IF REPEAT (WILL upgrade, e.g., 5/5):
|
|
|
|
|
|
→ [tap] → Fires OnCardDismissed
|
|
|
|
|
|
→ Shrink → RevealedState
|
|
|
|
|
|
|
|
|
|
|
|
2d. IF REPEAT (WILL upgrade, e.g., 5/5):
|
|
|
|
|
|
→ EnlargedRepeatState
|
|
|
|
|
|
→ Show progress bar (5/5) + blink
|
|
|
|
|
|
→ AUTO-UPGRADE (no tap needed)
|
|
|
|
|
|
→ Fires OnUpgradeTriggered
|
|
|
|
|
|
→ Update inventory
|
|
|
|
|
|
→ Check if new/repeat at higher rarity:
|
|
|
|
|
|
IF NEW at higher: → EnlargedNewState (higher rarity)
|
|
|
|
|
|
4. RevealedState (normal size, waiting)
|
|
|
|
|
|
→ [tap] → Fires OnCardDismissed
|
|
|
|
|
|
→ Shrink → RevealedState
|
|
|
|
|
|
|
|
|
|
|
|
5. [When all cards complete]
|
|
|
|
|
|
→ Fires OnCardInteractionComplete
|
|
|
|
|
|
→ Waits for all 3 cards to finish
|
|
|
|
|
|
|
|
|
|
|
|
4. [When all cards complete]
|
|
|
|
|
|
→ BoosterOpeningPage animates cards to album → Destroy
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### **Album Placement Flow:**
|
|
|
|
|
|
```
|
|
|
|
|
|
1. IdleState (card back in corner, hover enabled)
|
|
|
|
|
|
↓ [player clicks]
|
|
|
|
|
|
2. FlippingState (reveals which card it is)
|
|
|
|
|
|
→ OnFlipComplete
|
|
|
|
|
|
↓
|
|
|
|
|
|
3. RevealedState
|
|
|
|
|
|
→ OnCardInteractionComplete
|
|
|
|
|
|
↓ [player drags]
|
|
|
|
|
|
4. DraggingState (scaled up during drag)
|
|
|
|
|
|
↓ [drop in slot]
|
|
|
|
|
|
5. PlacedInSlotState (in album permanently)
|
|
|
|
|
|
↓ [player clicks]
|
|
|
|
|
|
6. AlbumEnlargedState
|
|
|
|
|
|
→ Fires OnEnlargeRequested (page shows backdrop, reparents)
|
|
|
|
|
|
↓ [player taps]
|
|
|
|
|
|
→ Fires OnShrinkRequested (page prepares)
|
|
|
|
|
|
→ Shrink animation
|
|
|
|
|
|
↓
|
|
|
|
|
|
5. PlacedInSlotState (back in slot)
|
2025-11-11 21:03:05 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Key Design Decisions
|
|
|
|
|
|
|
|
|
|
|
|
### 1. State-Owned Visuals
|
|
|
|
|
|
- State-specific GameObjects (CardBackVisual, NewCardBadge, etc.) are **children of their state GameObject**
|
|
|
|
|
|
- When state activates → children activate automatically
|
|
|
|
|
|
- When state deactivates → children deactivate automatically
|
|
|
|
|
|
- **No manual visibility management needed!**
|
|
|
|
|
|
|
|
|
|
|
|
### 2. Transform Animation
|
|
|
|
|
|
- **Root Card.transform** is animated for position/scale (affects all children via Unity hierarchy)
|
|
|
|
|
|
- **State child visuals** can be animated independently (e.g., rotating CardBackVisual during flip)
|
|
|
|
|
|
- States decide WHAT to animate, CardAnimator provides HOW
|
|
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
### 3. Shared Resources via CardContext
|
|
|
|
|
|
```csharp
|
|
|
|
|
|
public class CardContext : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
// Component references
|
|
|
|
|
|
public CardDisplay CardDisplay { get; }
|
|
|
|
|
|
public CardAnimator Animator { get; }
|
|
|
|
|
|
public AppleMachine StateMachine { get; }
|
|
|
|
|
|
public Transform RootTransform { get; }
|
|
|
|
|
|
|
|
|
|
|
|
// Card data
|
|
|
|
|
|
public CardData CardData { get; }
|
|
|
|
|
|
public bool IsNewCard { get; set; }
|
|
|
|
|
|
public int RepeatCardCount { get; set; }
|
|
|
|
|
|
public bool IsClickable { get; set; } // Prevents multi-flip in booster opening
|
|
|
|
|
|
|
|
|
|
|
|
// Events for external coordination (BoosterOpeningPage)
|
|
|
|
|
|
public event Action<CardContext> OnFlipComplete;
|
|
|
|
|
|
public event Action<CardContext> OnCardDismissed;
|
|
|
|
|
|
public event Action<CardContext> OnCardInteractionComplete;
|
|
|
|
|
|
public event Action<CardContext> OnUpgradeTriggered;
|
|
|
|
|
|
|
|
|
|
|
|
// Helper methods
|
|
|
|
|
|
public void FireFlipComplete();
|
|
|
|
|
|
public void FireCardDismissed();
|
|
|
|
|
|
public void FireCardInteractionComplete();
|
|
|
|
|
|
public void FireUpgradeTriggered();
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
|
|
|
|
|
### 4. State Transitions
|
|
|
|
|
|
States explicitly transition via `_context.StateMachine.ChangeState("StateName")`
|
|
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
Example:
|
|
|
|
|
|
```csharp
|
|
|
|
|
|
// In CardFlippingState.OnFlipComplete():
|
|
|
|
|
|
if (_context.IsNewCard)
|
|
|
|
|
|
_context.StateMachine.ChangeState("EnlargedNewState");
|
|
|
|
|
|
else if (_context.RepeatCardCount > 0)
|
|
|
|
|
|
_context.StateMachine.ChangeState("EnlargedRepeatState");
|
2025-11-11 21:03:05 +01:00
|
|
|
|
```
|
2025-11-12 11:58:01 +01:00
|
|
|
|
|
|
|
|
|
|
### 5. Progress Bar Architecture
|
|
|
|
|
|
**ProgressBarController Component:**
|
|
|
|
|
|
- Auto-detects child Image elements (5 images in GridLayout)
|
|
|
|
|
|
- Fills from bottom to top (element[0] = bottom)
|
|
|
|
|
|
- Blinks newest element with configurable timing
|
|
|
|
|
|
- Callback when animation completes
|
|
|
|
|
|
|
|
|
|
|
|
**Usage:**
|
|
|
|
|
|
```csharp
|
|
|
|
|
|
progressBar.ShowProgress(currentCount, maxCount, OnProgressComplete);
|
2025-11-11 21:03:05 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Files Created
|
|
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
### **Core Components:**
|
|
|
|
|
|
- `StateMachine/CardContext.cs` - Shared context + events
|
|
|
|
|
|
- `StateMachine/CardAnimator.cs` - Reusable animation methods (enlarge, shrink, flip, idle hover, etc.)
|
|
|
|
|
|
- `ProgressBarController.cs` - Progress bar UI controller with blink animation
|
|
|
|
|
|
|
|
|
|
|
|
### **Settings:**
|
|
|
|
|
|
- `Core/Settings/CardSystemSettings.cs` - ScriptableObject for all card animation timings
|
|
|
|
|
|
- `Core/Settings/ICardSystemSettings.cs` - Interface for settings access
|
|
|
|
|
|
|
|
|
|
|
|
### **State Implementations:**
|
|
|
|
|
|
- `States/CardIdleState.cs` - Owns CardBackVisual, idle hover, click to flip (with click blocking)
|
|
|
|
|
|
- `States/CardFlippingState.cs` - Owns CardBackVisual, flip animation, Legendary shortcut
|
|
|
|
|
|
- `States/CardRevealedState.cs` - Owns NewCardIdleBadge + RepeatCardIdleBadge, fires OnCardInteractionComplete
|
|
|
|
|
|
- `States/CardEnlargedNewState.cs` - Owns NewCardBadge, tap to shrink
|
|
|
|
|
|
- `States/CardEnlargedRepeatState.cs` - Owns RepeatText + ProgressBarUI, auto-upgrade logic
|
|
|
|
|
|
- `States/CardDraggingState.cs` - Drag handling for album placement
|
|
|
|
|
|
- `States/CardPlacedInSlotState.cs` - In album slot, click to enlarge
|
|
|
|
|
|
- `States/CardAlbumEnlargedState.cs` - Enlarged from album, tap to shrink
|
|
|
|
|
|
|
|
|
|
|
|
## Prefab Assembly Instructions
|
|
|
|
|
|
|
|
|
|
|
|
### **Card Prefab Hierarchy:**
|
|
|
|
|
|
```
|
|
|
|
|
|
Card (RectTransform)
|
|
|
|
|
|
├─ CardDisplay (existing prefab)
|
|
|
|
|
|
├─ CardContext (component)
|
|
|
|
|
|
├─ FlippingState (CardFlippingState component)
|
|
|
|
|
|
│ └─ CardBackVisual (Image)
|
|
|
|
|
|
├─ CardAnimator (component)
|
|
|
|
|
|
└─ CardStateMachine (AppleMachine)
|
|
|
|
|
|
├─ IdleState (CardIdleState component)
|
|
|
|
|
|
│ └─ CardBackVisual (Image)
|
|
|
|
|
|
├─ RevealedState (CardRevealedState component)
|
|
|
|
|
|
│ ├─ NewCardIdleBadge (Image/Text - "NEW!")
|
|
|
|
|
|
│ └─ RepeatCardIdleBadge (Image/Text - "REPEAT")
|
|
|
|
|
|
│ └─ ProgressBarContainer (GameObject)
|
|
|
|
|
|
│ └─ ProgressBarUI (prefab instance)
|
|
|
|
|
|
│ └─ NewCardBadge (Image/Text - "NEW CARD")
|
|
|
|
|
|
├─ EnlargedRepeatState (CardEnlargedRepeatState component)
|
|
|
|
|
|
│ ├─ RepeatText (Image/Text - "REPEAT CARD")
|
|
|
|
|
|
│ └─ ProgressBarUI (ProgressBarController component + 5 Image children)
|
|
|
|
|
|
├─ DraggingState (CardDraggingState component)
|
|
|
|
|
|
ProgressBarUI
|
|
|
|
|
|
├─ GridLayoutGroup (1 column, 5 rows, "Lower Right" corner start)
|
|
|
|
|
|
├─ ProgressElement1 (Image)
|
|
|
|
|
|
|
|
|
|
|
|
### **ProgressBarUI Prefab:**
|
|
|
|
|
|
```
|
|
|
|
|
|
ProgressBarUI (GameObject with ProgressBarController component)
|
|
|
|
|
|
└─ ProgressElement5 (Image)
|
|
|
|
|
|
├─ VerticalLayoutGroup (Reverse Arrangement enabled)
|
|
|
|
|
|
└─ Children (5 Images, auto-detected):
|
|
|
|
|
|
├─ ProgressElement1 (Image) - First child = 1/5
|
|
|
|
|
|
├─ ProgressElement2 (Image)
|
|
|
|
|
|
├─ ProgressElement3 (Image)
|
|
|
|
|
|
├─ ProgressElement4 (Image)
|
|
|
|
|
|
└─ ProgressElement5 (Image) - Last child = 5/5
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### **Component References to Assign:**
|
|
|
|
|
|
**CardContext:**
|
|
|
|
|
|
- cardDisplay → CardDisplay component
|
|
|
|
|
|
- cardAnimator → CardAnimator component
|
|
|
|
|
|
|
|
|
|
|
|
**CardIdleState:**
|
|
|
|
|
|
- cardBackVisual → CardBackVisual child GameObject
|
|
|
|
|
|
|
|
|
|
|
|
**CardFlippingState:**
|
|
|
|
|
|
- cardBackVisual → CardBackVisual child GameObject
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
**CardRevealedState:**
|
|
|
|
|
|
- progressBarContainer → ProgressBarContainer child GameObject
|
|
|
|
|
|
- progressBar → ProgressBarController component (on ProgressBarUI prefab)
|
|
|
|
|
|
- repeatCardIdleBadge → RepeatCardIdleBadge child GameObject
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
**CardEnlargedNewState:**
|
|
|
|
|
|
- newCardBadge → NewCardBadge child GameObject
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
**CardEnlargedRepeatState:**
|
|
|
|
|
|
- progressBar → ProgressBarController component (on ProgressBarUI child GameObject)
|
|
|
|
|
|
- repeatText → RepeatText child GameObject
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
## Integration with BoosterOpeningPage
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
```csharp
|
|
|
|
|
|
// When spawning cards:
|
|
|
|
|
|
Card card = Instantiate(cardPrefab);
|
|
|
|
|
|
CardContext context = card.GetComponent<CardContext>();
|
|
|
|
|
|
|
|
|
|
|
|
// Setup card data
|
|
|
|
|
|
context.SetupCard(cardData, isNew: isNewCard, repeatCount: ownedCount);
|
|
|
|
|
|
|
|
|
|
|
|
// All cards start clickable
|
|
|
|
|
|
context.IsClickable = true;
|
|
|
|
|
|
|
|
|
|
|
|
// Subscribe to events
|
|
|
|
|
|
context.OnFlipComplete += OnCardFlipComplete;
|
|
|
|
|
|
context.OnCardDismissed += OnCardDismissed;
|
|
|
|
|
|
context.OnCardInteractionComplete += OnCardInteractionComplete;
|
|
|
|
|
|
context.OnUpgradeTriggered += OnCardUpgraded;
|
|
|
|
|
|
|
|
|
|
|
|
// Start in IdleState
|
|
|
|
|
|
context.StateMachine.ChangeState("IdleState");
|
|
|
|
|
|
|
|
|
|
|
|
// When a card starts flipping, block all others
|
|
|
|
|
|
private void OnCardFlipComplete(CardContext flippingCard)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Disable all cards to prevent multi-flip
|
|
|
|
|
|
foreach (CardContext card in _allCards)
|
|
|
|
|
|
{
|
|
|
|
|
|
card.IsClickable = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Track completion
|
|
|
|
|
|
private void OnCardInteractionComplete(CardContext card)
|
|
|
|
|
|
{
|
|
|
|
|
|
_cardsCompletedInteraction++;
|
|
|
|
|
|
|
|
|
|
|
|
if (_cardsCompletedInteraction == 3)
|
|
|
|
|
|
{
|
|
|
|
|
|
AnimateCardsToAlbum(); // All cards revealed, animate to album
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// Re-enable unflipped cards
|
|
|
|
|
|
foreach (CardContext c in _allCards)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (c.StateMachine.CurrentState.name == "IdleState")
|
|
|
|
|
|
{
|
|
|
|
|
|
c.IsClickable = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
|
|
|
|
|
## Benefits vs Old System
|
|
|
|
|
|
|
|
|
|
|
|
| Aspect | Old System | New System |
|
|
|
|
|
|
|--------|-----------|------------|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
| Components per card | FlippableCard + AlbumCard + wrappers | 1 Card + states |
|
|
|
|
|
|
| Animation code duplication | ~200 lines across 5 files | 0 (shared CardAnimator) |
|
|
|
|
|
|
| State tracking | 12+ boolean flags (_isFlipped, _isFlipping, _isWaitingForTap, etc.) | 1 active state name |
|
|
|
|
|
|
| Visual element management | Manual SetActive() in 8+ places | Automatic via state activation |
|
|
|
|
|
|
| Adding new behaviors | Modify 3-4 components + events | Add 1 new state GameObject |
|
|
|
|
|
|
| Prefab nesting | FlippableCard → AlbumCard → CardDisplay (5 layers) | Card → States (flat hierarchy) |
|
|
|
|
|
|
| Debugging state | Check 12 booleans across files | Look at active state name in inspector |
|
|
|
|
|
|
| Progress bar logic | 50 lines in FlippableCard.ShowProgressBar() | Isolated in ProgressBarController |
|
|
|
|
|
|
| Upgrade logic | TriggerUpgradeTransition (80 lines in FlippableCard) | TriggerUpgrade (isolated in CardEnlargedRepeatState) |
|
|
|
|
|
|
| Event coordination | 4 events on FlippableCard, 2 on AlbumCard | 4 events on CardContext (centralized) |
|
|
|
|
|
|
|
|
|
|
|
|
## Testing Checklist
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] Booster opening: NEW card shows badge → tap → shrinks → shows NEW idle badge
|
|
|
|
|
|
- [ ] Booster opening: REPEAT card (2/5) shows REPEAT text + progress → blink → tap → shrinks → shows REPEAT idle badge
|
|
|
|
|
|
- [ ] Booster opening: REPEAT card (5/5) auto-upgrades → shows NEW at higher rarity
|
|
|
|
|
|
- [ ] Booster opening: Legendary repeat skips enlarge
|
|
|
|
|
|
- [ ] Booster opening: Click blocking prevents multi-flip
|
|
|
|
|
|
- [ ] Booster opening: All 3 cards complete → animate to album
|
|
|
|
|
|
- [ ] Album placement: Card in corner → click → reveals → drag → place in slot
|
|
|
|
|
|
- [ ] Album placement: Card in slot → click → enlarges → tap → shrinks back
|
|
|
|
|
|
- [ ] Cascading upgrades (Common → Uncommon → Rare in one reveal)
|
|
|
|
|
|
- [ ] Progress bar shows correctly (1/5, 2/5, 3/5, 4/5, 5/5)
|
|
|
|
|
|
- [ ] Progress bar blinks newest element
|
|
|
|
|
|
- [ ] Idle hover animation works in both flows
|
|
|
|
|
|
- [ ] Hover scale works on pointer enter/exit
|
|
|
|
|
|
|
|
|
|
|
|
## Integration Work Remaining
|
|
|
|
|
|
|
|
|
|
|
|
1. Update BoosterOpeningPage to use new Card prefab instead of FlippableCard
|
|
|
|
|
|
2. Update AlbumViewPage to use new Card prefab instead of AlbumCard
|
|
|
|
|
|
3. Migrate album placement drag/drop to use DraggingState
|
|
|
|
|
|
4. Remove old FlippableCard.cs and AlbumCard.cs after migration
|
|
|
|
|
|
5. **(Optional)** Add Jiggle() animation to CardAnimator for clicking inactive cards
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
## Migration Path
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
**Phase 1: Side-by-side (Current)**
|
|
|
|
|
|
- New state machine exists alongside old FlippableCard/AlbumCard
|
|
|
|
|
|
- Can test new system without breaking existing functionality
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
2025-11-12 11:58:01 +01:00
|
|
|
|
**Phase 2: Booster Opening Migration**
|
|
|
|
|
|
- Update BoosterOpeningPage to spawn new Card prefab
|
|
|
|
|
|
- Remove FlippableCard references
|
|
|
|
|
|
- Test all booster flows
|
|
|
|
|
|
|
|
|
|
|
|
**Phase 3: Album Migration**
|
|
|
|
|
|
- Update AlbumViewPage to spawn new Card prefab
|
|
|
|
|
|
- Remove AlbumCard references
|
|
|
|
|
|
- Test album placement and enlarge
|
|
|
|
|
|
|
|
|
|
|
|
**Phase 4: Cleanup**
|
|
|
|
|
|
- Delete FlippableCard.cs
|
|
|
|
|
|
- Delete AlbumCard.cs
|
|
|
|
|
|
- Delete old wrapper components
|
|
|
|
|
|
- Clean up unused prefab variants
|
|
|
|
|
|
|
|
|
|
|
|
## Example: Adding New Card Behavior
|
|
|
|
|
|
|
|
|
|
|
|
**Scenario:** Add a "Trading" state where card shows trade UI?
|
|
|
|
|
|
|
|
|
|
|
|
**Old system:**
|
|
|
|
|
|
1. Modify FlippableCard.cs (add boolean, methods, events)
|
|
|
|
|
|
2. Modify AlbumCard.cs (add pass-through logic)
|
|
|
|
|
|
3. Update 3-4 wrapper components
|
|
|
|
|
|
4. Add new events and subscriptions
|
|
|
|
|
|
5. Manually manage trade UI visibility
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
|
|
|
|
|
**New system:**
|
2025-11-12 11:58:01 +01:00
|
|
|
|
1. Create `CardTradingState.cs`:
|
|
|
|
|
|
```csharp
|
|
|
|
|
|
public class CardTradingState : AppleState
|
|
|
|
|
|
{
|
|
|
|
|
|
[SerializeField] private GameObject tradeUI;
|
|
|
|
|
|
|
|
|
|
|
|
public override void OnEnterState()
|
|
|
|
|
|
{
|
|
|
|
|
|
// tradeUI automatically activates with state!
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
2. Add TradingState GameObject under CardStateMachine
|
2025-11-11 21:03:05 +01:00
|
|
|
|
3. Add trade UI as child of TradingState
|
2025-11-12 11:58:01 +01:00
|
|
|
|
4. Call `ChangeState("TradingState")` from wherever needed
|
|
|
|
|
|
|
|
|
|
|
|
**Done! Zero other files modified.**
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Summary
|
|
|
|
|
|
|
|
|
|
|
|
The new state machine implementation successfully replicates all core FlippableCard/AlbumCard functionality with:
|
|
|
|
|
|
- ✅ Cleaner architecture (state pattern vs boolean soup)
|
|
|
|
|
|
- ✅ Less code duplication (shared CardAnimator)
|
|
|
|
|
|
- ✅ Easier debugging (visible state names)
|
|
|
|
|
|
- ✅ Simpler extension (add states vs modify monoliths)
|
|
|
|
|
|
- ✅ Better separation of concerns (each state owns its visuals)
|
|
|
|
|
|
|
|
|
|
|
|
**Status: Core implementation complete, ready for prefab assembly and integration testing.**
|
2025-11-11 21:03:05 +01:00
|
|
|
|
|
|
|
|
|
|
|