Stash half-assed work on testing scene
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Card State Machine Implementation Summary
|
||||
# Card State Machine Implementation Summary
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
@@ -6,17 +6,93 @@
|
||||
|
||||
```
|
||||
Card (RectTransform - primary animation target)
|
||||
├─ CardDisplay (always visible)
|
||||
├─ CardContext (shared references)
|
||||
├─ CardDisplay (always visible - shows card front)
|
||||
├─ CardContext (shared references + events)
|
||||
├─ CardAnimator (reusable animations)
|
||||
└─ CardStateMachine (AppleMachine)
|
||||
├─ IdleState/
|
||||
│ └─ CardBackVisual ← State owns this
|
||||
├─ FlippingState/
|
||||
│ └─ CardBackVisual ← State owns this
|
||||
├─ RevealedState/
|
||||
│ ├─ NewCardIdleBadge ← State owns this
|
||||
│ └─ RepeatCardIdleBadge ← State owns this
|
||||
├─ EnlargedNewState/
|
||||
│ └─ NewCardBadge ← State owns this
|
||||
└─ EnlargedRepeatState/
|
||||
└─ ProgressBarUI ← State owns this
|
||||
├─ 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)
|
||||
```
|
||||
|
||||
## Key Design Decisions
|
||||
@@ -32,81 +108,301 @@ Card (RectTransform - primary animation target)
|
||||
- **State child visuals** can be animated independently (e.g., rotating CardBackVisual during flip)
|
||||
- States decide WHAT to animate, CardAnimator provides HOW
|
||||
|
||||
### 3. Shared Resources
|
||||
- `CardContext` component provides states access to:
|
||||
- CardDisplay
|
||||
- CardAnimator
|
||||
- StateMachine
|
||||
- CardData
|
||||
- IsNewCard flag
|
||||
- States call `_context.Animator.PlayFlip(...)` instead of duplicating tween code
|
||||
### 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();
|
||||
}
|
||||
```
|
||||
|
||||
### 4. State Transitions
|
||||
States explicitly transition via `_context.StateMachine.ChangeState("StateName")`
|
||||
|
||||
Example flow:
|
||||
Example:
|
||||
```csharp
|
||||
// In CardFlippingState.OnFlipComplete():
|
||||
if (_context.IsNewCard)
|
||||
_context.StateMachine.ChangeState("EnlargedNewState");
|
||||
else if (_context.RepeatCardCount > 0)
|
||||
_context.StateMachine.ChangeState("EnlargedRepeatState");
|
||||
```
|
||||
IdleState
|
||||
[click] → FlippingState
|
||||
[flip complete + IsNew] → EnlargedNewState
|
||||
[tap] → RevealedState
|
||||
|
||||
### 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);
|
||||
```
|
||||
|
||||
## Files Created
|
||||
|
||||
**Core Components:**
|
||||
- `CardContext.cs` - Shared context accessible to all states
|
||||
- `CardAnimator.cs` - Reusable animation methods
|
||||
- `CardAnimationConfig.cs` - ScriptableObject for designer tweaks
|
||||
### **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
|
||||
|
||||
**State Implementations:**
|
||||
- `States/CardIdleState.cs` - Hover animation, click to flip
|
||||
- `States/CardFlippingState.cs` - Owns CardBackVisual, flip animation
|
||||
- `States/CardRevealedState.cs` - Waiting for interaction
|
||||
- `States/CardEnlargedNewState.cs` - Owns NewCardBadge, tap to dismiss
|
||||
- `States/CardEnlargedRepeatState.cs` - Owns ProgressBarUI, tap to dismiss
|
||||
### **Settings:**
|
||||
- `Core/Settings/CardSystemSettings.cs` - ScriptableObject for all card animation timings
|
||||
- `Core/Settings/ICardSystemSettings.cs` - Interface for settings access
|
||||
|
||||
## Next Steps
|
||||
### **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
|
||||
|
||||
1. **Create remaining states:**
|
||||
- `CardDraggingState` (for album placement flow)
|
||||
- `CardPlacedInSlotState` (album slot interaction)
|
||||
- `CardAlbumEnlargedState` (enlarge from album)
|
||||
## Prefab Assembly Instructions
|
||||
|
||||
2. **Build Card prefab:**
|
||||
- Setup hierarchy with state children
|
||||
- Assign CardBackVisual, NewCardBadge, ProgressBarUI to states
|
||||
- Create CardAnimationConfig asset
|
||||
### **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)
|
||||
|
||||
3. **Migrate existing code:**
|
||||
- Update BoosterOpeningPage to use new Card
|
||||
- Update AlbumViewPage to use new Card
|
||||
- Remove old wrapper scripts (FlippableCard, AlbumCard, etc.)
|
||||
### **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
|
||||
|
||||
**CardRevealedState:**
|
||||
- progressBarContainer → ProgressBarContainer child GameObject
|
||||
- progressBar → ProgressBarController component (on ProgressBarUI prefab)
|
||||
- repeatCardIdleBadge → RepeatCardIdleBadge child GameObject
|
||||
|
||||
**CardEnlargedNewState:**
|
||||
- newCardBadge → NewCardBadge child GameObject
|
||||
|
||||
**CardEnlargedRepeatState:**
|
||||
- progressBar → ProgressBarController component (on ProgressBarUI child GameObject)
|
||||
- repeatText → RepeatText child GameObject
|
||||
|
||||
## Integration with BoosterOpeningPage
|
||||
|
||||
```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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Benefits vs Old System
|
||||
|
||||
| Aspect | Old System | New System |
|
||||
|--------|-----------|------------|
|
||||
| Components per card | 5+ wrappers | 1 root + states |
|
||||
| Animation code duplication | ~150 lines across 4 files | 0 (shared CardAnimator) |
|
||||
| State tracking | 12+ boolean flags | 1 state machine |
|
||||
| Visual element management | Manual SetActive calls | Automatic via state activation |
|
||||
| Adding new behaviors | Modify 3-4 components | Add 1 new state GameObject |
|
||||
| Prefab nesting | 5 layers deep | Flat (states as children) |
|
||||
| Debugging state | Check 12 booleans | Look at active state name |
|
||||
| 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) |
|
||||
|
||||
## Example: Adding New State
|
||||
## Testing Checklist
|
||||
|
||||
Want to add a "Trading" state where card shows trade UI?
|
||||
- [ ] 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
|
||||
|
||||
**Old system:** Modify FlippableCard, AlbumCard, add new wrapper, update events, etc.
|
||||
## 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
|
||||
|
||||
## Migration Path
|
||||
|
||||
**Phase 1: Side-by-side (Current)**
|
||||
- New state machine exists alongside old FlippableCard/AlbumCard
|
||||
- Can test new system without breaking existing functionality
|
||||
|
||||
**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
|
||||
|
||||
**New system:**
|
||||
1. Create `CardTradingState.cs`
|
||||
2. Add `TradingState` GameObject under CardStateMachine
|
||||
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
|
||||
3. Add trade UI as child of TradingState
|
||||
4. Implement `OnEnterState()` to show UI
|
||||
5. Call `ChangeState("TradingState")` from wherever needed
|
||||
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.**
|
||||
|
||||
Done! No other files touched.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user