Files
AppleHillsProduction/docs/cards_wip/card_prefab_assembly_guide.md

426 lines
14 KiB
Markdown
Raw Normal View History

2025-11-11 21:03:05 +01:00
# Card Prefab Assembly Guide
## Overview
This guide walks you through creating the new Card prefab with state machine architecture while integrating with existing CardDisplay components.
---
## Step 1: Create CardAnimationConfig Asset
1. In Unity Project window, right-click in `Assets/Data/CardSystem/`
2. Select **Create → AppleHills → Card Animation Config**
3. Name it `CardAnimationConfig`
4. Configure settings (these match your current FlippableCard settings):
- **Flip Animation**
- Flip Duration: `0.6`
- Flip Scale Punch: `1.1`
- **Enlarge Animation**
- Enlarged Scale: `2.5`
- Scale Duration: `0.3`
- **Hover Animation**
- Hover Height: `10`
- Hover Duration: `1.5`
- Hover Scale Multiplier: `1.05`
- **Drag Animation**
- Drag Scale: `1.1`
- Snap Duration: `0.4`
---
## Step 2: Create Base Card Prefab
### Create Root GameObject
1. In Hierarchy, right-click → **Create Empty**
2. Name it `Card`
3. Add Component → **Rect Transform** (converts to UI element)
4. Set **Anchors** to center-middle
5. Set **Size** to `200 x 280` (standard card size)
### Add Core Components to Root
1. **Add CardContext component:**
- Click **Add Component** → search `CardContext`
- Leave references empty for now (will auto-find)
2. **Add CardAnimator component:**
- Click **Add Component** → search `CardAnimator`
- Drag `CardAnimationConfig` asset to **Config** field
3. **Add Card component:**
- Click **Add Component** → search `Card`
- Set **Initial State** to `IdleState`
---
## Step 3: Add CardDisplay (From Existing Prefab)
### Option A: If you have existing CardDisplay prefab
1. Drag `CardDisplay` prefab into hierarchy as child of `Card`
2. Position at `(0, 0, 0)` local position
3. Ensure it fills the card area
### Option B: Create CardDisplay from scratch
1. Right-click `Card` in hierarchy → **Create Empty**
2. Name it `CardDisplay`
3. Add Component → **Card Display** (your existing script)
4. Setup UI elements as children:
- Add **Image** for card image
- Add **TextMeshProUGUI** for card name
- Add **Image** for frame
- Add **Image** for overlay
- Add **Image** for background
- Add **Image** for zone shape
5. Assign these to CardDisplay component fields
---
## Step 4: Create State Machine Hierarchy
### Create StateMachine GameObject
1. Right-click `Card`**Create Empty**
2. Name it `CardStateMachine`
3. Add Component → **Apple Machine** (from Pixelplacement)
4. Configure AppleMachine:
- **Verbose**: unchecked (unless debugging)
- **Allow Reentry**: unchecked
- **Return To Default On Disable**: checked
### Create State GameObjects (as children of CardStateMachine)
For each state, follow this pattern:
#### 1. IdleState
1. Right-click `CardStateMachine`**Create Empty**
2. Name it `IdleState`
3. Add Component → **Card Idle State**
4. **Create CardBackVisual child:**
2025-11-12 11:58:01 +01:00
- Right-click `IdleState`**UI → Image**
2025-11-11 21:03:05 +01:00
- Name it `CardBackVisual`
- Set **Anchors** to stretch-stretch
- Set **Left/Right/Top/Bottom** to `0`
- Assign your card back sprite to **Source Image**
2025-11-12 11:58:01 +01:00
- Drag this to **Card Back Visual** field on CardIdleState component
- **Note:** This state handles both idle behavior AND flip animation
2025-11-11 21:03:05 +01:00
2025-11-12 11:58:01 +01:00
#### 2. RevealedState
2025-11-11 21:03:05 +01:00
1. Right-click `CardStateMachine`**Create Empty**
2. Name it `RevealedState`
3. Add Component → **Card Revealed State**
2025-11-12 11:58:01 +01:00
4. **Create idle badge visuals:**
- Right-click `RevealedState`**Create Empty**
- Name it `NewCardIdleBadge`
- Add child **UI → Image** for small badge background
- Add child **UI → TextMeshProUGUI** for "NEW!" text
- Position at top-right corner (e.g., X offset +70, Y offset +100)
- Drag `NewCardIdleBadge` to **New Card Idle Badge** field
- Right-click `RevealedState`**Create Empty**
- Name it `RepeatCardIdleBadge`
- Add child **UI → Image** for small badge background
- Add child **UI → TextMeshProUGUI** for "REPEAT" text
- Position at top-right corner (same position as NEW badge)
- Drag `RepeatCardIdleBadge` to **Repeat Card Idle Badge** field
#### 3. EnlargedNewState
2025-11-11 21:03:05 +01:00
1. Right-click `CardStateMachine`**Create Empty**
2. Name it `EnlargedNewState`
3. Add Component → **Card Enlarged New State**
4. **Create NewCardBadge child:**
- Right-click `EnlargedNewState`**Create Empty**
- Name it `NewCardBadge`
- Add child **UI → Image** for badge background
- Add child **UI → TextMeshProUGUI** for "NEW CARD" text
- Position badge at top of card (e.g., Y offset +100)
- Drag parent `NewCardBadge` to **New Card Badge** field on CardEnlargedNewState
2025-11-12 11:58:01 +01:00
#### 4. EnlargedRepeatState
2025-11-11 21:03:05 +01:00
1. Right-click `CardStateMachine`**Create Empty**
2. Name it `EnlargedRepeatState`
3. Add Component → **Card Enlarged Repeat State**
4. **Create ProgressBarUI child:**
2025-11-12 11:58:01 +01:00
- Right-click `EnlargedRepeatState`**Create Empty** (or drag your ProgressBarUI prefab)
- Name it `ProgressBarUI`
- Add **ProgressBarController** component to this GameObject
- Add **VerticalLayoutGroup** component (enable "Reverse Arrangement")
- Create 5 child **UI → Image** elements under ProgressBarUI
- Name them `ProgressElement1` through `ProgressElement5`
2025-11-11 21:03:05 +01:00
- Position at bottom of card (e.g., Y offset -100)
2025-11-12 11:58:01 +01:00
- Drag `ProgressBarController` component to **Progress Bar** field on CardEnlargedRepeatState
2025-11-11 21:03:05 +01:00
2025-11-12 11:58:01 +01:00
#### 5. DraggingState
2025-11-11 21:03:05 +01:00
1. Right-click `CardStateMachine`**Create Empty**
2. Name it `DraggingState`
3. Add Component → **Card Dragging State**
4. Set **Drag Scale** to `1.1`
5. **No child visuals needed** for this state
2025-11-12 11:58:01 +01:00
#### 6. PlacedInSlotState
2025-11-11 21:03:05 +01:00
1. Right-click `CardStateMachine`**Create Empty**
2. Name it `PlacedInSlotState`
3. Add Component → **Card Placed In Slot State**
4. **No child visuals needed** for this state
2025-11-12 11:58:01 +01:00
#### 7. AlbumEnlargedState
2025-11-11 21:03:05 +01:00
1. Right-click `CardStateMachine`**Create Empty**
2. Name it `AlbumEnlargedState`
3. Add Component → **Card Album Enlarged State**
4. **No child visuals needed** for this state
---
## Step 5: Wire Up References
### On CardStateMachine (AppleMachine component)
1. Select `CardStateMachine` GameObject
2. Set **Default State** to `IdleState` GameObject (drag from hierarchy)
### On Card Root (Card component)
1. Select root `Card` GameObject
2. **Context** should auto-find CardContext component
3. **Animator** should auto-find CardAnimator component
4. **State Machine** should auto-find CardStateMachine/AppleMachine
5. If not auto-found, drag components manually
### On CardContext Component
1. Select root `Card` GameObject
2. In CardContext component:
- **Card Display**: Drag `CardDisplay` child GameObject
- **Card Animator**: Should auto-find on same GameObject
- **State Machine**: Should auto-find CardStateMachine child
---
## Step 6: Test the State Machine
### Test in Editor (Play Mode)
1. Select root `Card` in hierarchy
2. In Card component, call `SetupCard()` from inspector (you'll need test data)
3. Watch the state machine transition through states
4. Check **CardStateMachine → Current State** field to see active state
5. Click the card to trigger state transitions
### Debug Tips
- Enable **Verbose** on AppleMachine to see state change logs
- Watch hierarchy - active state GameObject will be enabled (blue icon)
- Inactive states will be disabled (gray icon)
- State-owned visuals (CardBackVisual, NewCardBadge, etc.) should activate/deactivate with their parent state
---
## Step 7: Save as Prefab
1. Drag the root `Card` GameObject from hierarchy to `Assets/Prefabs/UI/CardSystem/`
2. Name it `Card.prefab`
3. Delete the instance from hierarchy (prefab is saved)
---
## Step 8: Integration with Existing Code
### Spawning New Cards (BoosterOpeningPage example)
**Old code:**
```csharp
GameObject cardObj = Instantiate(flippableCardPrefab, cardDisplayContainer);
FlippableCard card = cardObj.GetComponent<FlippableCard>();
card.SetupCard(cardData);
```
**New code:**
```csharp
GameObject cardObj = Instantiate(cardPrefab, cardDisplayContainer);
Card card = cardObj.GetComponent<Card>();
card.SetupForBoosterReveal(cardData, isNew: true);
```
### Placing Cards in Album (AlbumViewPage example)
**Old code:**
```csharp
AlbumCard albumCard = Instantiate(albumCardPrefab, slot.transform);
albumCard.SetupCard(cardData);
albumCard.SetParentSlot(slot);
```
**New code:**
```csharp
Card card = Instantiate(cardPrefab, slot.transform);
card.SetupForAlbumSlot(cardData, slot);
```
### Listening to State Events
**Example - Listening for card reveal:**
```csharp
Card card = GetComponent<Card>();
var flippingState = card.GetStateComponent<CardFlippingState>("FlippingState");
// Subscribe to flip complete (you may need to add custom events)
// Or check current state:
if (card.GetCurrentStateName() == "RevealedState")
{
// Card was revealed
}
```
---
## Step 9: Create Prefab Variants (Optional)
You can create variants for different card contexts:
### BoosterCard Variant
1. Right-click `Card.prefab`**Create → Prefab Variant**
2. Name it `BoosterCard.prefab`
3. Adjust initial state to `IdleState`
4. Customize appearance if needed
### AlbumCard Variant
1. Right-click `Card.prefab`**Create → Prefab Variant**
2. Name it `AlbumCard.prefab`
3. Adjust initial state to `PlacedInSlotState`
4. Remove states not needed (like IdleState, FlippingState if cards are pre-placed)
---
## Hierarchy Reference (Final Structure)
```
Card (RectTransform)
├─ [CardContext component]
├─ [CardAnimator component]
├─ [Card component]
├─ CardDisplay
│ ├─ CardImage (Image)
│ ├─ CardNameText (TextMeshProUGUI)
│ ├─ FrameImage (Image)
│ ├─ OverlayImage (Image)
│ ├─ BackgroundImage (Image)
│ └─ ZoneShapeImage (Image)
└─ CardStateMachine
├─ [AppleMachine component]
├─ IdleState
2025-11-12 11:58:01 +01:00
│ ├─ [CardIdleState component]
2025-11-11 21:03:05 +01:00
│ └─ CardBackVisual (Image)
├─ RevealedState
2025-11-12 11:58:01 +01:00
│ ├─ [CardRevealedState component]
│ ├─ NewCardIdleBadge
│ │ ├─ BadgeBackground (Image)
│ │ └─ BadgeText (TextMeshProUGUI - "NEW!")
│ └─ RepeatCardIdleBadge
│ ├─ BadgeBackground (Image)
│ └─ BadgeText (TextMeshProUGUI - "REPEAT")
2025-11-11 21:03:05 +01:00
├─ EnlargedNewState
│ ├─ [CardEnlargedNewState component]
│ └─ NewCardBadge
│ ├─ BadgeBackground (Image)
2025-11-12 11:58:01 +01:00
│ └─ BadgeText (TextMeshProUGUI - "NEW CARD")
2025-11-11 21:03:05 +01:00
├─ EnlargedRepeatState
│ ├─ [CardEnlargedRepeatState component]
2025-11-12 11:58:01 +01:00
│ └─ ProgressBarUI
│ ├─ [ProgressBarController component]
│ ├─ [VerticalLayoutGroup component - Reverse Arrangement]
│ ├─ ProgressElement1 (Image - 1/5)
│ ├─ ProgressElement2 (Image - 2/5)
│ ├─ ProgressElement3 (Image - 3/5)
│ ├─ ProgressElement4 (Image - 4/5)
│ └─ ProgressElement5 (Image - 5/5)
2025-11-11 21:03:05 +01:00
├─ DraggingState
│ └─ [CardDraggingState component]
├─ PlacedInSlotState
│ └─ [CardPlacedInSlotState component]
└─ AlbumEnlargedState
└─ [CardAlbumEnlargedState component]
```
---
## Troubleshooting
### Issue: States not transitioning
- **Check:** AppleMachine **Default State** is assigned
- **Check:** State names match exactly (case-sensitive: "IdleState" not "idlestate")
- **Check:** Enable **Verbose** on AppleMachine to see logs
### Issue: Visuals not showing
- **Check:** State-owned visuals (CardBackVisual, etc.) are assigned in state components
- **Check:** Images have sprites assigned
- **Check:** RectTransforms are sized properly (not 0x0)
### Issue: CardContext references null
- **Check:** CardDisplay is assigned on CardContext component
- **Check:** CardAnimator has CardAnimationConfig asset assigned
- **Check:** All components are on correct GameObjects
### Issue: Animations not playing
- **Check:** CardAnimationConfig asset is assigned to CardAnimator
- **Check:** Tween system (Pixelplacement) is in project
- **Check:** Config values are not zero
### Issue: Click not working
- **Check:** Canvas has **Graphic Raycaster** component
- **Check:** EventSystem exists in scene
- **Check:** Card has **CanvasGroup** with **Blocks Raycasts** enabled (or Image component)
- **Check:** State components implement IPointerClickHandler (IdleState, RevealedState, etc.)
---
## Migration Checklist
- [ ] Created CardAnimationConfig asset
- [ ] Created base Card prefab with all components
2025-11-12 11:58:01 +01:00
- [ ] Created all 7 state GameObjects under CardStateMachine
2025-11-11 21:03:05 +01:00
- [ ] Assigned state-owned visuals (CardBackVisual, NewCardBadge, ProgressBarUI)
- [ ] Wired up all component references
- [ ] Tested state transitions in Play mode
- [ ] Saved as prefab
- [ ] Updated BoosterOpeningPage to use new Card prefab
- [ ] Updated AlbumViewPage to use new Card prefab
- [ ] Tested booster opening flow
- [ ] Tested album placement flow
- [ ] Tested enlarge/shrink interactions
- [ ] (Optional) Deprecated old prefabs (FlippableCard, AlbumCard, etc.)
---
## Next Steps After Prefab Creation
1. **Test Booster Opening Flow:**
- Open BoosterOpeningPage scene
- Replace FlippableCard prefab references with Card prefab
- Test pack opening, card reveal, new/repeat states
2. **Test Album Flow:**
- Open AlbumViewPage scene
- Replace AlbumCard prefab references with Card prefab
- Test placing cards in slots, enlarging from album
3. **Performance Testing:**
- Spawn 10+ cards at once
- Check frame rate, tween performance
- Verify no memory leaks from state transitions
4. **Clean Up Old Code:**
- Once new system is stable, deprecate:
- `FlippableCard.cs`
- `AlbumCard.cs`
- `AlbumCardPlacementDraggable.cs` (if fully replaced)
- Keep `CardDisplay.cs` (still used!)
- Archive old prefabs for reference
---
## Success Criteria
2025-11-12 11:58:01 +01:00
✅ Card prefab created with 7 functional states
✅ State transitions work (Idle → Revealed → Enlarged, etc.)
2025-11-11 21:03:05 +01:00
✅ State-owned visuals activate/deactivate automatically
✅ Animations play correctly (flip, enlarge, hover)
✅ Click interactions work in all states
✅ Integration with BoosterOpeningPage works
✅ Integration with AlbumViewPage works
✅ No console errors during state transitions
✅ Performance is acceptable (60fps with multiple cards)
Once all criteria met, you have successfully migrated to the new card system! 🎉