Cleanup
This commit is contained in:
@@ -1,147 +0,0 @@
|
|||||||
# 🎯 Quick Setup Checklist - Copy This!
|
|
||||||
|
|
||||||
## ✅ What's Done (By AI)
|
|
||||||
|
|
||||||
- ✅ Created `BoosterVisual.prefab` in `Assets/Prefabs/UI/DragAndDrop/`
|
|
||||||
- ✅ Created `BoosterPackPrefab.prefab` in `Assets/Prefabs/UI/Cards/`
|
|
||||||
- ✅ Created `FlippableCardPrefab.prefab` in `Assets/Prefabs/UI/Cards/`
|
|
||||||
- ✅ BoosterVisual has TiltParent, ShakeParent, PackImage structure
|
|
||||||
- ✅ All components are added
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 What YOU Need To Do (Quick Version)
|
|
||||||
|
|
||||||
### **1. BoosterVisual.prefab** (2 minutes)
|
|
||||||
```
|
|
||||||
Open prefab → Select root
|
|
||||||
├─ Assign: TiltParent → to "Tilt Parent" field
|
|
||||||
├─ Assign: ShakeParent → to "Shake Parent" field
|
|
||||||
├─ Assign: TiltParent/PackImage → to "Pack Image" field
|
|
||||||
└─ Assign: YOUR SPRITE → to "Pack Sprite" field
|
|
||||||
|
|
||||||
Select TiltParent/PackImage
|
|
||||||
└─ Uncheck "Raycast Target" on Image component
|
|
||||||
```
|
|
||||||
|
|
||||||
### **2. BoosterPackPrefab.prefab** (1 minute)
|
|
||||||
```
|
|
||||||
Open prefab → Select root
|
|
||||||
├─ Set size: 200x300
|
|
||||||
├─ Check "Raycast Target" on Image component
|
|
||||||
├─ Assign: BoosterVisual.prefab → to "Visual Prefab" field
|
|
||||||
├─ Check: "Can Tap To Open"
|
|
||||||
└─ Set: "Max Taps To Open" = 3
|
|
||||||
```
|
|
||||||
|
|
||||||
### **3. FlippableCardPrefab.prefab** (1 minute)
|
|
||||||
```
|
|
||||||
Open prefab → Select root
|
|
||||||
├─ Set size: 200x300
|
|
||||||
└─ Assign: YOUR CARD BACK SPRITE → to Image sprite
|
|
||||||
```
|
|
||||||
|
|
||||||
### **4. BoosterOpeningPage.prefab** (10 minutes)
|
|
||||||
```
|
|
||||||
Open prefab → Add children manually:
|
|
||||||
|
|
||||||
CREATE THESE CHILDREN:
|
|
||||||
├─ CloseButton (UI > Button)
|
|
||||||
├─ BottomRightContainer (Empty + SlotContainer component)
|
|
||||||
│ ├─ Slot_0 (Empty + DraggableSlot)
|
|
||||||
│ ├─ Slot_1 (Empty + DraggableSlot)
|
|
||||||
│ └─ Slot_2 (Empty + DraggableSlot)
|
|
||||||
├─ CenterSlot (Empty + DraggableSlot)
|
|
||||||
│ └─ IMPORTANT: Apply Scale = ✓, Scale = (2,2,1)
|
|
||||||
├─ CardDisplayContainer (Empty)
|
|
||||||
└─ BoosterInstances (Empty)
|
|
||||||
├─ Drag BoosterPackPrefab → name "BoosterPack_0" → Uncheck Active
|
|
||||||
├─ Drag BoosterPackPrefab → name "BoosterPack_1" → Uncheck Active
|
|
||||||
└─ Drag BoosterPackPrefab → name "BoosterPack_2" → Uncheck Active
|
|
||||||
|
|
||||||
WIRE UP ROOT COMPONENT:
|
|
||||||
Select BoosterOpeningPage root → Assign all references:
|
|
||||||
├─ Close Button → CloseButton
|
|
||||||
├─ Booster Pack Instances [0-2] → BoosterPack_0, 1, 2
|
|
||||||
├─ Bottom Right Slots → BottomRightContainer
|
|
||||||
├─ Center Opening Slot → CenterSlot
|
|
||||||
├─ Card Display Container → CardDisplayContainer
|
|
||||||
└─ Flippable Card Prefab → FlippableCardPrefab.prefab
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔍 Critical Settings
|
|
||||||
|
|
||||||
### **CenterSlot (Most Important!)**
|
|
||||||
```yaml
|
|
||||||
Apply Scale To Occupant: ✓ CHECK THIS!
|
|
||||||
Occupant Scale: (2, 2, 1) # Makes booster 2x bigger
|
|
||||||
Filter By Type: ✓
|
|
||||||
Allowed Type Names: ["BoosterPackDraggable"]
|
|
||||||
```
|
|
||||||
|
|
||||||
### **BottomRightContainer SlotContainer**
|
|
||||||
```yaml
|
|
||||||
Layout Type: Vertical
|
|
||||||
Spacing: 120
|
|
||||||
Center Slots: ✓
|
|
||||||
Auto Register Children: ✓
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Each Bottom Slot (Slot_0, 1, 2)**
|
|
||||||
```yaml
|
|
||||||
Filter By Type: ✓
|
|
||||||
Allowed Type Names: ["BoosterPackDraggable"]
|
|
||||||
Apply Scale To Occupant: ☐ UNCHECKED (normal size)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚡ Super Quick Start
|
|
||||||
|
|
||||||
**Fastest path to testing:**
|
|
||||||
|
|
||||||
1. Open `BoosterVisual.prefab` → Assign 4 references → Save
|
|
||||||
2. Open `BoosterPackPrefab.prefab` → Assign BoosterVisual, check tap settings → Save
|
|
||||||
3. Open `FlippableCardPrefab.prefab` → Assign sprite → Save
|
|
||||||
4. Open `BoosterOpeningPage.prefab` → Build child structure (see above) → Wire references → Save
|
|
||||||
5. Test!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Sprite Assignments Needed
|
|
||||||
|
|
||||||
You need to assign these sprites:
|
|
||||||
|
|
||||||
1. **Booster Pack Sprite** → BoosterVisual/PackImage
|
|
||||||
2. **Card Back Sprite** → FlippableCardPrefab
|
|
||||||
3. **Optional: Background** → BoosterOpeningPage/Background
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐛 If Something Doesn't Work
|
|
||||||
|
|
||||||
**Can't drag booster:**
|
|
||||||
→ Check BoosterPackPrefab base Image has raycastTarget = ✓
|
|
||||||
|
|
||||||
**Booster doesn't scale in center:**
|
|
||||||
→ Check CenterSlot "Apply Scale To Occupant" = ✓
|
|
||||||
|
|
||||||
**Taps don't work:**
|
|
||||||
→ Check "Can Tap To Open" = ✓ on booster
|
|
||||||
|
|
||||||
**No boosters show:**
|
|
||||||
→ Check they're assigned in BoosterOpeningPage component
|
|
||||||
→ Check CardSystemManager has boosters available
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📄 Full Details
|
|
||||||
|
|
||||||
See `SETUP_COMPLETE_Manual_Steps.md` for detailed step-by-step instructions!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Estimated Time:** 15-20 minutes total 🕐
|
|
||||||
|
|
||||||
@@ -1,343 +0,0 @@
|
|||||||
# ✅ Booster Opening System - Auto-Generated Prefabs & Manual Setup
|
|
||||||
|
|
||||||
## 🎉 What I Created For You
|
|
||||||
|
|
||||||
I've successfully created the following prefabs using Unity MCP:
|
|
||||||
|
|
||||||
### ✅ **Created Prefabs:**
|
|
||||||
|
|
||||||
1. **`Assets/Prefabs/UI/DragAndDrop/BoosterVisual.prefab`**
|
|
||||||
- Base visual prefab for booster packs
|
|
||||||
- Has: Canvas, CanvasGroup, BoosterPackVisual component
|
|
||||||
- Has children: TiltParent (with PackImage), ShakeParent
|
|
||||||
|
|
||||||
2. **`Assets/Prefabs/UI/Cards/BoosterPackPrefab.prefab`**
|
|
||||||
- Main draggable booster prefab
|
|
||||||
- Has: Image, BoosterPackDraggable component
|
|
||||||
- Ready for visual prefab assignment
|
|
||||||
|
|
||||||
3. **`Assets/Prefabs/UI/Cards/FlippableCardPrefab.prefab`**
|
|
||||||
- Card reveal prefab
|
|
||||||
- Has: Image, CardDisplay, Button components
|
|
||||||
- Ready for sprite assignment
|
|
||||||
|
|
||||||
### 📋 **Existing Prefab:**
|
|
||||||
4. **`Assets/Prefabs/UI/Cards/BoosterOpeningPage.prefab`**
|
|
||||||
- Already has: RectTransform, CanvasGroup, BoosterOpeningPage component
|
|
||||||
- Needs child structure added (see below)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛠️ Manual Setup Required
|
|
||||||
|
|
||||||
Due to Unity MCP limitations with editing existing prefabs, you'll need to complete the setup manually. Here's EXACTLY what to do:
|
|
||||||
|
|
||||||
### **STEP 1: Configure BoosterVisual Prefab**
|
|
||||||
|
|
||||||
1. Open `Assets/Prefabs/UI/DragAndDrop/BoosterVisual.prefab`
|
|
||||||
2. Select the root `BoosterVisual` object
|
|
||||||
3. In **BoosterPackVisual** component, assign references:
|
|
||||||
- Tilt Parent: Drag `TiltParent` child
|
|
||||||
- Shake Parent: Drag `ShakeParent` child
|
|
||||||
- Pack Image: Drag `TiltParent/PackImage`
|
|
||||||
- Pack Sprite: **[YOU ASSIGN]** - Your booster pack sprite asset
|
|
||||||
4. Set these values:
|
|
||||||
```
|
|
||||||
Follow Speed: 30
|
|
||||||
Rotation Amount: 20
|
|
||||||
Rotation Speed: 20
|
|
||||||
Auto Tilt Amount: 30
|
|
||||||
Manual Tilt Amount: 20
|
|
||||||
Tilt Speed: 20
|
|
||||||
Use Scale Animations: ✓
|
|
||||||
Scale On Hover: 1.15
|
|
||||||
Scale On Drag: 1.25
|
|
||||||
Use Idle Animation: ✓
|
|
||||||
Idle Animation Speed: 1
|
|
||||||
Opening Scale Punch: 0.5
|
|
||||||
Opening Rotation Punch: 360
|
|
||||||
Opening Duration: 0.5
|
|
||||||
```
|
|
||||||
5. Select `TiltParent/PackImage`
|
|
||||||
6. Set **Image** component:
|
|
||||||
- Raycast Target: ☐ **UNCHECK THIS**
|
|
||||||
- Size: 180x280 (or adjust to fit)
|
|
||||||
7. Save prefab
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **STEP 2: Configure BoosterPackPrefab**
|
|
||||||
|
|
||||||
1. Open `Assets/Prefabs/UI/Cards/BoosterPackPrefab.prefab`
|
|
||||||
2. Select root `BoosterPackPrefab`
|
|
||||||
3. Set **RectTransform**:
|
|
||||||
- Width: 200
|
|
||||||
- Height: 300
|
|
||||||
4. Set **Image** component:
|
|
||||||
- Sprite: **[YOU ASSIGN]** - Placeholder or your booster sprite
|
|
||||||
- Raycast Target: ✓ **MUST BE CHECKED**
|
|
||||||
5. Set **BoosterPackDraggable** component:
|
|
||||||
```
|
|
||||||
Move Speed: 50
|
|
||||||
Smooth Movement: ✓
|
|
||||||
Snap Duration: 0.3
|
|
||||||
Visual Prefab: [Drag BoosterVisual.prefab]
|
|
||||||
Instantiate Visual: ✓
|
|
||||||
Is Selectable: ✓
|
|
||||||
Selection Offset: 50
|
|
||||||
Can Open On Drop: ☐
|
|
||||||
Can Open On Double Click: ☐
|
|
||||||
Can Tap To Open: ✓
|
|
||||||
Max Taps To Open: 3
|
|
||||||
```
|
|
||||||
6. Save prefab
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **STEP 3: Configure FlippableCardPrefab**
|
|
||||||
|
|
||||||
1. Open `Assets/Prefabs/UI/Cards/FlippableCardPrefab.prefab`
|
|
||||||
2. Select root `FlippableCardPrefab`
|
|
||||||
3. Set **RectTransform**:
|
|
||||||
- Width: 200
|
|
||||||
- Height: 300
|
|
||||||
4. Set **Image** component:
|
|
||||||
- Sprite: **[YOU ASSIGN]** - Card back sprite
|
|
||||||
- Raycast Target: ✓
|
|
||||||
5. **CardDisplay** component will be configured at runtime
|
|
||||||
6. **Button** component is ready (OnClick added at runtime)
|
|
||||||
7. Save prefab
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **STEP 4: Build BoosterOpeningPage Structure**
|
|
||||||
|
|
||||||
⚠️ **IMPORTANT:** You need to manually add children to the BoosterOpeningPage prefab.
|
|
||||||
|
|
||||||
1. Open `Assets/Prefabs/UI/Cards/BoosterOpeningPage.prefab` in Prefab mode
|
|
||||||
2. Add the following structure:
|
|
||||||
|
|
||||||
```
|
|
||||||
BoosterOpeningPage (root - already exists)
|
|
||||||
├── Background (optional)
|
|
||||||
│ └── [Create: UI > Image]
|
|
||||||
│ └── [Set: Full screen, dark semi-transparent]
|
|
||||||
│
|
|
||||||
├── CloseButton
|
|
||||||
│ └── [Create: UI > Button - TextMeshPro]
|
|
||||||
│ └── [Position: Top-right corner]
|
|
||||||
│ └── [Text: "X" or "Close"]
|
|
||||||
│
|
|
||||||
├── BottomRightContainer
|
|
||||||
│ └── [Create: Empty GameObject]
|
|
||||||
│ └── [Add Component: SlotContainer]
|
|
||||||
│ └── [Position: X=800, Y=-400 (adjust for your canvas)]
|
|
||||||
│ └── [Anchor: Bottom-Right]
|
|
||||||
│ └── [Children: 3 slots below]
|
|
||||||
│ │
|
|
||||||
│ ├── Slot_0
|
|
||||||
│ │ └── [Create: Empty GameObject]
|
|
||||||
│ │ └── [Add Component: DraggableSlot]
|
|
||||||
│ │ └── [Size: 150x200]
|
|
||||||
│ │
|
|
||||||
│ ├── Slot_1
|
|
||||||
│ │ └── [Same as Slot_0]
|
|
||||||
│ │
|
|
||||||
│ └── Slot_2
|
|
||||||
│ └── [Same as Slot_0]
|
|
||||||
│
|
|
||||||
├── CenterSlot
|
|
||||||
│ └── [Create: Empty GameObject]
|
|
||||||
│ └── [Add Component: DraggableSlot]
|
|
||||||
│ └── [Position: Center (0, 0)]
|
|
||||||
│ └── [Size: 300x400]
|
|
||||||
│ └── [Anchor: Middle Center]
|
|
||||||
│
|
|
||||||
├── CardDisplayContainer
|
|
||||||
│ └── [Create: Empty GameObject]
|
|
||||||
│ └── [Position: Center (0, -100)]
|
|
||||||
│ └── [Anchor: Middle Center]
|
|
||||||
│
|
|
||||||
└── BoosterInstances
|
|
||||||
└── [Create: Empty GameObject]
|
|
||||||
└── [Children: 3 booster instances below]
|
|
||||||
│
|
|
||||||
├── BoosterPack_0
|
|
||||||
│ └── [Drag in: BoosterPackPrefab]
|
|
||||||
│ └── [Set Active: ☐ UNCHECKED]
|
|
||||||
│
|
|
||||||
├── BoosterPack_1
|
|
||||||
│ └── [Drag in: BoosterPackPrefab]
|
|
||||||
│ └── [Set Active: ☐ UNCHECKED]
|
|
||||||
│
|
|
||||||
└── BoosterPack_2
|
|
||||||
└── [Drag in: BoosterPackPrefab]
|
|
||||||
└── [Set Active: ☐ UNCHECKED]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **STEP 5: Configure BottomRightContainer (SlotContainer)**
|
|
||||||
|
|
||||||
1. Select `BottomRightContainer`
|
|
||||||
2. Set **RectTransform**:
|
|
||||||
- Anchor: Bottom-Right
|
|
||||||
- Pivot: (1, 0)
|
|
||||||
- Position: X=-100, Y=100 (offset from corner)
|
|
||||||
3. Set **SlotContainer** component:
|
|
||||||
```
|
|
||||||
Layout Type: Vertical
|
|
||||||
Spacing: 120
|
|
||||||
Center Slots: ✓
|
|
||||||
Auto Register Children: ✓
|
|
||||||
```
|
|
||||||
4. For each child slot (Slot_0, Slot_1, Slot_2):
|
|
||||||
- Width: 150, Height: 200
|
|
||||||
- **DraggableSlot** settings:
|
|
||||||
```
|
|
||||||
Slot Index: 0, 1, 2 (respectively)
|
|
||||||
Is Locked: ☐
|
|
||||||
Filter By Type: ✓
|
|
||||||
Allowed Type Names: ["BoosterPackDraggable"]
|
|
||||||
Apply Scale To Occupant: ☐
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **STEP 6: Configure CenterSlot (Opening Slot)**
|
|
||||||
|
|
||||||
1. Select `CenterSlot`
|
|
||||||
2. Set **RectTransform**:
|
|
||||||
- Anchor: Middle Center
|
|
||||||
- Position: (0, 0)
|
|
||||||
- Width: 300, Height: 400
|
|
||||||
3. Set **DraggableSlot** component:
|
|
||||||
```
|
|
||||||
Slot Index: 0
|
|
||||||
Is Locked: ☐
|
|
||||||
Filter By Type: ✓
|
|
||||||
Allowed Type Names: ["BoosterPackDraggable"]
|
|
||||||
Apply Scale To Occupant: ✓ ← IMPORTANT!
|
|
||||||
Occupant Scale: (2, 2, 1) ← IMPORTANT!
|
|
||||||
Scale Transition Duration: 0.3
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **STEP 7: Wire Up BoosterOpeningPage Component**
|
|
||||||
|
|
||||||
1. Select root `BoosterOpeningPage`
|
|
||||||
2. In **BoosterOpeningPage** component, assign:
|
|
||||||
```
|
|
||||||
[UI References]
|
|
||||||
Canvas Group: [Auto-assigned or drag it]
|
|
||||||
Close Button: [Drag CloseButton]
|
|
||||||
|
|
||||||
[Booster Management]
|
|
||||||
Booster Pack Instances (Array size: 3):
|
|
||||||
Element 0: [Drag BoosterPack_0]
|
|
||||||
Element 1: [Drag BoosterPack_1]
|
|
||||||
Element 2: [Drag BoosterPack_2]
|
|
||||||
Bottom Right Slots: [Drag BottomRightContainer]
|
|
||||||
Center Opening Slot: [Drag CenterSlot]
|
|
||||||
|
|
||||||
[Card Display]
|
|
||||||
Card Display Container: [Drag CardDisplayContainer]
|
|
||||||
Flippable Card Prefab: [Drag FlippableCardPrefab.prefab]
|
|
||||||
Card Spacing: 150
|
|
||||||
|
|
||||||
[Settings]
|
|
||||||
Card Reveal Delay: 0.5
|
|
||||||
Booster Disappear Duration: 0.5
|
|
||||||
Transition Duration: 0.3
|
|
||||||
```
|
|
||||||
3. Save prefab
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Final Checklist
|
|
||||||
|
|
||||||
Before testing, verify:
|
|
||||||
|
|
||||||
### **BoosterVisual.prefab:**
|
|
||||||
- [ ] TiltParent and ShakeParent are assigned in component
|
|
||||||
- [ ] Pack Image is assigned in component
|
|
||||||
- [ ] Pack Sprite is assigned (your asset)
|
|
||||||
- [ ] PackImage has raycastTarget = false
|
|
||||||
|
|
||||||
### **BoosterPackPrefab.prefab:**
|
|
||||||
- [ ] Size is 200x300
|
|
||||||
- [ ] Base Image has raycastTarget = TRUE
|
|
||||||
- [ ] Visual Prefab is assigned (BoosterVisual)
|
|
||||||
- [ ] Can Tap To Open = ✓
|
|
||||||
- [ ] Max Taps To Open = 3
|
|
||||||
|
|
||||||
### **FlippableCardPrefab.prefab:**
|
|
||||||
- [ ] Size is 200x300
|
|
||||||
- [ ] Has card back sprite assigned
|
|
||||||
- [ ] Has CardDisplay component
|
|
||||||
- [ ] Has Button component
|
|
||||||
|
|
||||||
### **BoosterOpeningPage.prefab:**
|
|
||||||
- [ ] Has all children created (see structure above)
|
|
||||||
- [ ] BottomRightContainer has 3 DraggableSlots
|
|
||||||
- [ ] CenterSlot has scale settings configured
|
|
||||||
- [ ] BoosterInstances has 3 inactive booster prefab instances
|
|
||||||
- [ ] All references assigned in BoosterOpeningPage component
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎮 Testing
|
|
||||||
|
|
||||||
1. **Test in Scene:**
|
|
||||||
- Add BoosterOpeningPage prefab to your scene
|
|
||||||
- Make sure it's a child of your Canvas
|
|
||||||
- Start inactive (UIPage system controls visibility)
|
|
||||||
|
|
||||||
2. **Test Boosters:**
|
|
||||||
- Set CardSystemManager booster count to 3
|
|
||||||
- Open album → Click booster button
|
|
||||||
- Should see 3 boosters in bottom-right
|
|
||||||
|
|
||||||
3. **Test Drag:**
|
|
||||||
- Drag a booster to center
|
|
||||||
- Should scale up to 2x
|
|
||||||
|
|
||||||
4. **Test Taps:**
|
|
||||||
- Tap booster 3 times
|
|
||||||
- Should shake progressively
|
|
||||||
- Should disappear and show cards
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 What You Still Need To Do
|
|
||||||
|
|
||||||
1. **Assign Sprites:**
|
|
||||||
- Booster pack sprite to BoosterVisual/PackImage
|
|
||||||
- Card back sprite to FlippableCardPrefab
|
|
||||||
|
|
||||||
2. **Build Page Structure:**
|
|
||||||
- Add all children to BoosterOpeningPage as outlined
|
|
||||||
- Position elements appropriately for your canvas size
|
|
||||||
|
|
||||||
3. **Wire References:**
|
|
||||||
- Assign all the references in BoosterOpeningPage component
|
|
||||||
|
|
||||||
4. **Visual Polish:**
|
|
||||||
- Add optional particle effects to BoosterVisual
|
|
||||||
- Style the close button
|
|
||||||
- Add background image
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 Tips
|
|
||||||
|
|
||||||
- **Canvas Size:** Adjust positions based on your canvas reference resolution
|
|
||||||
- **Testing:** Test one piece at a time (boosters, then slots, then page)
|
|
||||||
- **Sprites:** Use placeholder sprites initially, replace later
|
|
||||||
- **Debugging:** Enable Gizmos to see slot positions
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
🎉 **Three prefabs are ready! Just follow the manual steps above to complete the setup!** 🎉
|
|
||||||
|
|
||||||
@@ -1,395 +0,0 @@
|
|||||||
# Booster Opening System - Complete Setup Guide
|
|
||||||
|
|
||||||
## 📋 Overview
|
|
||||||
This guide walks you through setting up the complete booster opening flow, from the Album page to opening packs and revealing cards.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 What Was Implemented
|
|
||||||
|
|
||||||
### **Core Components Enhanced:**
|
|
||||||
1. **DraggableSlot** - Added scale control for occupants
|
|
||||||
2. **BoosterPackDraggable** - Added tap-to-shake functionality
|
|
||||||
3. **BoosterPackVisual** - Added progressive shake animations
|
|
||||||
4. **BoosterOpeningPage** - Complete flow implementation
|
|
||||||
5. **AlbumViewPage** - Updated to pass booster count
|
|
||||||
|
|
||||||
### **Flow Summary:**
|
|
||||||
1. Album page shows booster buttons → Click → Opens BoosterOpeningPage
|
|
||||||
2. Opening page shows draggable boosters in bottom-right
|
|
||||||
3. Player taps or drags booster to center slot
|
|
||||||
4. Player taps booster X times (configurable, default 3)
|
|
||||||
5. Booster disappears, 3 card backs appear
|
|
||||||
6. Player clicks cards to reveal them one-by-one
|
|
||||||
7. After all revealed → Show next booster OR close page
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🏗️ Scene Setup Instructions
|
|
||||||
|
|
||||||
### **Step 1: Create the BoosterOpeningPage GameObject**
|
|
||||||
|
|
||||||
1. **In your scene hierarchy:**
|
|
||||||
- Create an empty GameObject named `BoosterOpeningPage`
|
|
||||||
- Add component: `BoosterOpeningPage` script
|
|
||||||
- Add component: `Canvas Group` (for fade transitions)
|
|
||||||
- Ensure it's a child of your Canvas
|
|
||||||
|
|
||||||
2. **Create UI Structure:**
|
|
||||||
```
|
|
||||||
BoosterOpeningPage (BoosterOpeningPage component)
|
|
||||||
├── Background (Image - optional dark overlay)
|
|
||||||
├── CloseButton (Button)
|
|
||||||
├── BottomRightContainer (SlotContainer)
|
|
||||||
│ ├── Slot_0 (DraggableSlot)
|
|
||||||
│ │ └── BoosterPack_0 (BoosterPackDraggable prefab instance)
|
|
||||||
│ ├── Slot_1 (DraggableSlot)
|
|
||||||
│ │ └── BoosterPack_1 (BoosterPackDraggable prefab instance)
|
|
||||||
│ └── Slot_2 (DraggableSlot)
|
|
||||||
│ └── BoosterPack_2 (BoosterPackDraggable prefab instance)
|
|
||||||
├── CenterSlot (DraggableSlot)
|
|
||||||
└── CardDisplayContainer (Empty RectTransform)
|
|
||||||
```
|
|
||||||
|
|
||||||
> **💡 Tip:** Boosters are parented directly to their starting slots! This makes authoring easier and the hierarchy cleaner. No separate container needed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📐 Detailed Component Setup
|
|
||||||
|
|
||||||
### **A. Bottom-Right Slot Container**
|
|
||||||
|
|
||||||
**GameObject Setup:**
|
|
||||||
- Name: `BottomRightContainer`
|
|
||||||
- Component: `SlotContainer`
|
|
||||||
- Position: Bottom-right of screen (e.g., anchored to bottom-right)
|
|
||||||
- Recommended position: X=800, Y=-400 (adjust for your canvas size)
|
|
||||||
|
|
||||||
**SlotContainer Settings:**
|
|
||||||
- Layout Type: `Vertical` (or `Custom` for hand-authored positions - see custom_layout_guide.md)
|
|
||||||
- Spacing: `120` (ignored if Layout Type = Custom)
|
|
||||||
- Center Slots: ✓ (ignored if Layout Type = Custom)
|
|
||||||
- Auto Register Children: ✓
|
|
||||||
|
|
||||||
> **💡 Tip:** Want artistic, scattered slot positions? Set Layout Type to `Custom` and manually position each slot in the Scene View. See `custom_layout_guide.md` for details!
|
|
||||||
|
|
||||||
**Child Slots (Slot_0, Slot_1, Slot_2):**
|
|
||||||
- Add component: `DraggableSlot` to each
|
|
||||||
- Size: 150x200 (adjust to your booster size)
|
|
||||||
- Settings:
|
|
||||||
- Filter By Type: ✓
|
|
||||||
- Allowed Type Names: `BoosterPackDraggable`
|
|
||||||
- Apply Scale To Occupant: ☐ (leave normal size)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **B. Center Opening Slot**
|
|
||||||
|
|
||||||
**GameObject Setup:**
|
|
||||||
- Name: `CenterSlot`
|
|
||||||
- Component: `DraggableSlot`
|
|
||||||
- Position: Center of screen (X=0, Y=0)
|
|
||||||
- Size: 300x400 (larger than boosters)
|
|
||||||
|
|
||||||
**DraggableSlot Settings:**
|
|
||||||
- Filter By Type: ✓
|
|
||||||
- Allowed Type Names: `BoosterPackDraggable`
|
|
||||||
- **Apply Scale To Occupant: ✓** ← Important!
|
|
||||||
- **Occupant Scale: (2, 2, 1)** ← Makes booster 2x bigger
|
|
||||||
- Scale Transition Duration: `0.3`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **C. Card Display Container**
|
|
||||||
|
|
||||||
**GameObject Setup:**
|
|
||||||
- Name: `CardDisplayContainer`
|
|
||||||
- Component: `RectTransform` only
|
|
||||||
- Position: Center of screen (X=0, Y=-100)
|
|
||||||
- This is where revealed cards will spawn
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **D. Booster Pack Instances**
|
|
||||||
|
|
||||||
**Setup as Slot Children (Recommended):**
|
|
||||||
|
|
||||||
**Create a single BoosterPackPrefab with visual as a child:**
|
|
||||||
|
|
||||||
**BoosterPackPrefab Structure:**
|
|
||||||
```
|
|
||||||
BoosterPackPrefab
|
|
||||||
├── BoosterPackDraggable (component)
|
|
||||||
├── CanvasGroup (component - for raycast control)
|
|
||||||
└── Visual (child GameObject)
|
|
||||||
├── Canvas (component - for z-order control)
|
|
||||||
├── CanvasGroup (component - for alpha fading)
|
|
||||||
├── BoosterPackVisual (component)
|
|
||||||
├── ShakeParent (RectTransform - position/rotation punch effects)
|
|
||||||
│ └── TiltParent (RectTransform - continuous smooth rotation)
|
|
||||||
│ └── PackImage (Image - your booster sprite, raycastTarget = false)
|
|
||||||
└── GlowEffect (ParticleSystem - optional)
|
|
||||||
```
|
|
||||||
|
|
||||||
**BoosterPackDraggable Settings:**
|
|
||||||
- **Visual Prefab:** Leave empty (using child visual instead)
|
|
||||||
- **Instantiate Visual:** ☐ unchecked (child visual is auto-detected)
|
|
||||||
- Can Open On Drop: ☐
|
|
||||||
- Can Open On Double Click: ☐
|
|
||||||
- **Can Tap To Open: ✓**
|
|
||||||
- **Max Taps To Open: 3**
|
|
||||||
|
|
||||||
**BoosterPackVisual Settings (on the Visual child):**
|
|
||||||
- Canvas: Auto-assigned or drag the Canvas component
|
|
||||||
- Canvas Group: Auto-assigned or drag the CanvasGroup component
|
|
||||||
- Tilt Parent: Drag `TiltParent`
|
|
||||||
- Shake Parent: Drag `ShakeParent`
|
|
||||||
- Pack Image: Drag `PackImage`
|
|
||||||
- Pack Sprite: Assign your booster sprite asset
|
|
||||||
- Glow Effect: Optional ParticleSystem
|
|
||||||
- Glow Transform: Optional (for rotation)
|
|
||||||
|
|
||||||
> **📝 Simplified Approach!** The visual is now a **direct child** of the BoosterPackPrefab, making authoring much easier. The system auto-detects child visuals using `GetComponentInChildren<DraggableVisual>()`. This gives you:
|
|
||||||
> - ✅ Full visual authoring control in the prefab
|
|
||||||
> - ✅ See exactly what your booster looks like
|
|
||||||
> - ✅ No separate prefab files to manage
|
|
||||||
> - ✅ Simpler hierarchy and setup
|
|
||||||
>
|
|
||||||
> The visual still follows with smooth lerp/delay and all animations work the same!
|
|
||||||
|
|
||||||
> **📝 Note on Hierarchy:** ShakeParent and TiltParent are **nested RectTransforms** (ShakeParent → TiltParent → PackImage) so PackImage gets BOTH effects combined: shake (discrete position/rotation tweens) AND tilt (continuous smooth rotation). This nesting allows transform inheritance through Unity's parent-child chain.
|
|
||||||
|
|
||||||
> **📝 Note on Raycast Control:** The root BoosterPackPrefab uses CanvasGroup's `blocksRaycasts` for raycast toggling during drag. Visual children (PackImage, etc.) should have `raycastTarget = false` so clicks reach the root.
|
|
||||||
|
|
||||||
> **💡 Advanced Option:** If you prefer the old pattern (separate prefab files), you can still use it by assigning a prefab to `Visual Prefab` and checking `Instantiate Visual`. The system supports both patterns - it checks for a child visual first, then falls back to instantiation if configured.
|
|
||||||
|
|
||||||
3. **Add to Slots:**
|
|
||||||
- Drag BoosterPackPrefab as child of `Slot_0` → Name it `BoosterPack_0`
|
|
||||||
- Drag BoosterPackPrefab as child of `Slot_1` → Name it `BoosterPack_1`
|
|
||||||
- Drag BoosterPackPrefab as child of `Slot_2` → Name it `BoosterPack_2`
|
|
||||||
- Set each booster's **Active state to ☐ UNCHECKED** (starts inactive)
|
|
||||||
- Position: (0, 0) local position (centered in slot)
|
|
||||||
|
|
||||||
> **💡 Why Parent to Slots?** The code calls `AssignToSlot()` which reparents anyway, so starting as a child of the slot makes authoring cleaner and more visual. You can see exactly where boosters will appear!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **E. Flippable Card Prefab**
|
|
||||||
|
|
||||||
**For now (placeholder):**
|
|
||||||
1. Create a simple prefab named `FlippableCardPrefab`
|
|
||||||
2. Structure:
|
|
||||||
```
|
|
||||||
FlippableCardPrefab
|
|
||||||
├── RectTransform (200x300)
|
|
||||||
├── CardDisplay (component)
|
|
||||||
├── Image (card back sprite initially)
|
|
||||||
└── Button (will be added at runtime if not present)
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Important:**
|
|
||||||
- The card should show a "back" sprite initially
|
|
||||||
- When clicked, `CardDisplay.SetupCard()` will be called
|
|
||||||
- In the future, add flip animation here
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **F. BoosterOpeningPage Component Configuration**
|
|
||||||
|
|
||||||
**In the Inspector:**
|
|
||||||
|
|
||||||
**UI References:**
|
|
||||||
- Canvas Group: Auto-assigned or drag the CanvasGroup
|
|
||||||
- Close Button: Drag your close button
|
|
||||||
|
|
||||||
**Booster Management:**
|
|
||||||
- Booster Pack Instances: **Array size = 3**
|
|
||||||
- Element 0: `BoosterPack_0`
|
|
||||||
- Element 1: `BoosterPack_1`
|
|
||||||
- Element 2: `BoosterPack_2`
|
|
||||||
- Bottom Right Slots: Drag `BottomRightContainer`
|
|
||||||
- Center Opening Slot: Drag `CenterSlot`
|
|
||||||
|
|
||||||
**Card Display:**
|
|
||||||
- Card Display Container: Drag `CardDisplayContainer`
|
|
||||||
- Flippable Card Prefab: Drag your card prefab
|
|
||||||
- Card Spacing: `150` (distance between cards)
|
|
||||||
|
|
||||||
**Settings:**
|
|
||||||
- Card Reveal Delay: `0.5`
|
|
||||||
- Booster Disappear Duration: `0.5`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Creating the Booster Pack Visual Prefab
|
|
||||||
|
|
||||||
### **Booster Visual Structure:**
|
|
||||||
|
|
||||||
```
|
|
||||||
BoosterVisual (BoosterPackVisual component)
|
|
||||||
├── Canvas (component - sort order controlled at runtime)
|
|
||||||
├── CanvasGroup (component - for fading)
|
|
||||||
├── ShakeParent (RectTransform - outer animation layer)
|
|
||||||
│ └── TiltParent (RectTransform - inner animation layer)
|
|
||||||
│ ├── PackImage (Image - your booster pack sprite)
|
|
||||||
│ └── FrameImage (Image - optional frame/border)
|
|
||||||
└── GlowEffect (Particle System - optional sparkles)
|
|
||||||
```
|
|
||||||
|
|
||||||
> **💡 Animation Chain:** ShakeParent contains TiltParent, which contains the visuals. This nesting means PackImage gets BOTH shake (position/rotation punch) AND tilt (smooth continuous rotation) effects combined through Unity's transform hierarchy. Both are RectTransforms since this is UI.
|
|
||||||
|
|
||||||
### **Component Settings:**
|
|
||||||
|
|
||||||
**BoosterPackVisual:**
|
|
||||||
- Canvas: Auto-assigned
|
|
||||||
- Canvas Group: Auto-assigned
|
|
||||||
- Tilt Parent: Drag `TiltParent`
|
|
||||||
- Shake Parent: Drag `ShakeParent`
|
|
||||||
- Pack Image: Drag the `PackImage`
|
|
||||||
- Pack Sprite: Assign your booster sprite asset
|
|
||||||
|
|
||||||
**Visual Animation Settings:**
|
|
||||||
- Follow Speed: `30`
|
|
||||||
- Rotation Amount: `20`
|
|
||||||
- Tilt Speed: `20`
|
|
||||||
- Use Idle Animation: ✓
|
|
||||||
- Idle Animation Speed: `1`
|
|
||||||
- Opening Scale Punch: `0.5`
|
|
||||||
- Opening Rotation Punch: `360`
|
|
||||||
- Opening Duration: `0.5`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔗 Connecting to AlbumViewPage
|
|
||||||
|
|
||||||
**In your AlbumViewPage Inspector:**
|
|
||||||
- Booster Opening Page: Drag your `BoosterOpeningPage` GameObject
|
|
||||||
- Booster Pack Buttons: Array of booster button GameObjects (already configured)
|
|
||||||
|
|
||||||
**That's it!** The AlbumViewPage script already has the updated code to pass booster count.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎮 Testing the Flow
|
|
||||||
|
|
||||||
### **Test Checklist:**
|
|
||||||
|
|
||||||
1. **Setup Test:**
|
|
||||||
- ✓ BoosterOpeningPage exists in scene
|
|
||||||
- ✓ All slots configured
|
|
||||||
- ✓ Booster instances assigned
|
|
||||||
- ✓ AlbumViewPage has reference to opening page
|
|
||||||
|
|
||||||
2. **Manual Booster Count:**
|
|
||||||
- In CardSystemManager, set initial booster count to 3
|
|
||||||
- Or use the editor tool to add boosters
|
|
||||||
|
|
||||||
3. **Test Flow:**
|
|
||||||
1. Open album → Should see 3 booster buttons
|
|
||||||
2. Click a booster button → Opens BoosterOpeningPage
|
|
||||||
3. Should see 3 boosters in bottom-right
|
|
||||||
4. **Drag Test:** Drag a booster to center → Should scale up 2x
|
|
||||||
5. **Tap Test:** Tap the booster 3 times:
|
|
||||||
- Tap 1: Small shake
|
|
||||||
- Tap 2: Medium shake
|
|
||||||
- Tap 3: Big shake → Booster disappears
|
|
||||||
6. Should see 3 card backs appear
|
|
||||||
7. Click each card → Should reveal (show CardDisplay)
|
|
||||||
8. After all revealed → Should show next booster OR close page
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚙️ Configuration Options
|
|
||||||
|
|
||||||
### **Adjusting Tap Count:**
|
|
||||||
- Select any BoosterPackDraggable
|
|
||||||
- Change `Max Taps To Open` (3 is default)
|
|
||||||
|
|
||||||
### **Adjusting Booster Cap:**
|
|
||||||
- In BoosterOpeningPage, change `Booster Pack Instances` array size
|
|
||||||
- Add/remove booster instances
|
|
||||||
- Bottom-right slots should match (add more Slot children)
|
|
||||||
|
|
||||||
### **Adjusting Center Slot Scale:**
|
|
||||||
- Select `CenterSlot`
|
|
||||||
- Change `Occupant Scale` (2,2,1 = 2x size)
|
|
||||||
|
|
||||||
### **Card Spacing:**
|
|
||||||
- In BoosterOpeningPage, adjust `Card Spacing` (150 default)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐛 Troubleshooting
|
|
||||||
|
|
||||||
### **Problem: Boosters don't appear**
|
|
||||||
- Check: `Booster Pack Instances` array is filled
|
|
||||||
- Check: CardSystemManager has boosters available
|
|
||||||
- Check: AlbumViewPage passes booster count correctly
|
|
||||||
|
|
||||||
### **Problem: Can't drag booster to center**
|
|
||||||
- Check: CenterSlot has `Filter By Type` with `BoosterPackDraggable`
|
|
||||||
- Check: CenterSlot is not locked initially
|
|
||||||
- Check: Booster has Image with `raycastTarget = true` on base object
|
|
||||||
|
|
||||||
### **Problem: Tapping doesn't work**
|
|
||||||
- Check: BoosterPackDraggable has `Can Tap To Open` enabled
|
|
||||||
- Check: Booster is in the center slot (tap only works when slotted)
|
|
||||||
- Check: Visual children have `raycastTarget = false` so taps reach the base
|
|
||||||
|
|
||||||
### **Problem: Booster doesn't scale up in center**
|
|
||||||
- Check: CenterSlot has `Apply Scale To Occupant` enabled
|
|
||||||
- Check: `Occupant Scale` is set (e.g., 2,2,1)
|
|
||||||
|
|
||||||
### **Problem: Cards don't reveal**
|
|
||||||
- Check: `Flippable Card Prefab` is assigned
|
|
||||||
- Check: Prefab has CardDisplay component
|
|
||||||
- Check: CardDisplay can receive card data
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Visual Polish (Optional Next Steps)
|
|
||||||
|
|
||||||
### **Enhance Card Flip:**
|
|
||||||
- Add rotation animation when revealing
|
|
||||||
- Use DOTween or Tween for 3D flip effect
|
|
||||||
- Particle effects on reveal
|
|
||||||
|
|
||||||
### **Booster Opening Effects:**
|
|
||||||
- More dramatic particles when opening
|
|
||||||
- Sound effects on taps and opening
|
|
||||||
- Screen shake on final tap
|
|
||||||
|
|
||||||
### **Transition Polish:**
|
|
||||||
- Boosters fly in on page open
|
|
||||||
- Cards fly out after revealing
|
|
||||||
- Smooth transitions between boosters
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Summary
|
|
||||||
|
|
||||||
**You now have:**
|
|
||||||
✅ Complete booster opening flow
|
|
||||||
✅ Tap-to-shake interaction (3 taps default)
|
|
||||||
✅ Drag-and-drop alternative
|
|
||||||
✅ Card reveal system (click to flip)
|
|
||||||
✅ Auto-progression to next booster
|
|
||||||
✅ Auto-close when no boosters left
|
|
||||||
✅ Scalable system (adjust array size for more boosters)
|
|
||||||
|
|
||||||
**Next Steps:**
|
|
||||||
1. Create your visual assets (booster sprites, card backs)
|
|
||||||
2. Set up the scene structure as outlined
|
|
||||||
3. Configure the BoosterOpeningPage component
|
|
||||||
4. Test the flow
|
|
||||||
5. Polish with animations and effects
|
|
||||||
|
|
||||||
**Need Help?**
|
|
||||||
- Reference the existing drag-and-drop documentation
|
|
||||||
- Check CardSystem documentation for card data structure
|
|
||||||
- Test individual components in isolation first
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
🎉 **Happy Booster Opening!** 🎉
|
|
||||||
|
|
||||||
@@ -1,342 +0,0 @@
|
|||||||
# Booster Pack Prefab Structure Guide
|
|
||||||
|
|
||||||
## 🎨 Complete Booster Pack Prefab Setup
|
|
||||||
|
|
||||||
This guide shows you exactly how to structure your booster pack prefabs for the opening system.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📦 BoosterPackDraggable Prefab Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
BoosterPackPrefab (RectTransform)
|
|
||||||
│
|
|
||||||
├── [Components on Root]
|
|
||||||
│ ├── RectTransform (200x300 size recommended)
|
|
||||||
│ ├── Image (IMPORTANT: raycastTarget = TRUE - for clicking/dragging)
|
|
||||||
│ ├── BoosterPackDraggable (script)
|
|
||||||
│ └── Canvas Group (optional - for fading)
|
|
||||||
│
|
|
||||||
└── Visual (Child GameObject)
|
|
||||||
└── [BoosterPackVisual Prefab Instance]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎭 BoosterPackVisual Prefab Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
BoosterVisual (RectTransform)
|
|
||||||
│
|
|
||||||
├── [Components on Root]
|
|
||||||
│ ├── RectTransform (same size as parent)
|
|
||||||
│ ├── Canvas (will be controlled at runtime)
|
|
||||||
│ ├── CanvasGroup (for alpha transitions)
|
|
||||||
│ └── BoosterPackVisual (script)
|
|
||||||
│
|
|
||||||
├── TiltParent (Empty Transform)
|
|
||||||
│ │ [This rotates for 3D tilt effect]
|
|
||||||
│ │
|
|
||||||
│ ├── PackImage (Image)
|
|
||||||
│ │ ├── Sprite: Your booster pack sprite
|
|
||||||
│ │ ├── raycastTarget: FALSE
|
|
||||||
│ │ └── Size: Slightly smaller than parent
|
|
||||||
│ │
|
|
||||||
│ ├── FrameImage (Image - optional)
|
|
||||||
│ │ ├── Sprite: Border/frame decoration
|
|
||||||
│ │ └── raycastTarget: FALSE
|
|
||||||
│ │
|
|
||||||
│ └── RarityIndicator (Image - optional)
|
|
||||||
│ ├── Sprite: Rarity gem/star
|
|
||||||
│ └── raycastTarget: FALSE
|
|
||||||
│
|
|
||||||
├── ShakeParent (Empty Transform)
|
|
||||||
│ │ [This is used for shake offset]
|
|
||||||
│ └── (Currently empty, reserved for effects)
|
|
||||||
│
|
|
||||||
└── GlowEffect (Particle System - optional)
|
|
||||||
├── Shape: Circle
|
|
||||||
├── Start Size: 5-10
|
|
||||||
├── Start Color: Golden/sparkly
|
|
||||||
├── Emission Rate: 10-20
|
|
||||||
└── Renderer: Sort Order = 1 (above images)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚙️ Component Configuration
|
|
||||||
|
|
||||||
### **BoosterPackDraggable Settings:**
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
[Draggable Settings]
|
|
||||||
Move Speed: 50
|
|
||||||
Smooth Movement: ✓
|
|
||||||
Snap Duration: 0.3
|
|
||||||
|
|
||||||
[Visual]
|
|
||||||
Visual Prefab: (Assign BoosterVisual prefab)
|
|
||||||
Instantiate Visual: ✓
|
|
||||||
Visual Parent: (Leave empty - uses canvas)
|
|
||||||
|
|
||||||
[Selection]
|
|
||||||
Is Selectable: ✓
|
|
||||||
Selection Offset: 50
|
|
||||||
|
|
||||||
[Booster Pack Settings]
|
|
||||||
Can Open On Drop: ☐
|
|
||||||
Can Open On Double Click: ☐
|
|
||||||
|
|
||||||
[Tap to Open]
|
|
||||||
Can Tap To Open: ✓
|
|
||||||
Max Taps To Open: 3
|
|
||||||
```
|
|
||||||
|
|
||||||
### **BoosterPackVisual Settings:**
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
[References]
|
|
||||||
Canvas: (Auto-assigned)
|
|
||||||
Canvas Group: (Auto-assigned)
|
|
||||||
Tilt Parent: (Drag TiltParent object)
|
|
||||||
Shake Parent: (Drag ShakeParent object)
|
|
||||||
|
|
||||||
[Follow Parameters]
|
|
||||||
Follow Speed: 30
|
|
||||||
Use Follow Delay: ✓
|
|
||||||
|
|
||||||
[Rotation/Tilt Parameters]
|
|
||||||
Rotation Amount: 20
|
|
||||||
Rotation Speed: 20
|
|
||||||
Auto Tilt Amount: 30
|
|
||||||
Manual Tilt Amount: 20
|
|
||||||
Tilt Speed: 20
|
|
||||||
|
|
||||||
[Scale Parameters]
|
|
||||||
Use Scale Animations: ✓
|
|
||||||
Scale On Hover: 1.15
|
|
||||||
Scale On Drag: 1.25
|
|
||||||
Scale Transition Duration: 0.15
|
|
||||||
|
|
||||||
[Idle Animation]
|
|
||||||
Use Idle Animation: ✓
|
|
||||||
Idle Animation Speed: 1
|
|
||||||
|
|
||||||
[Booster Pack Visual]
|
|
||||||
Pack Image: (Drag PackImage)
|
|
||||||
Pack Sprite: (Assign your sprite asset)
|
|
||||||
Glow Effect: (Drag particle system if using)
|
|
||||||
Glow Transform: (Drag particle transform if using)
|
|
||||||
|
|
||||||
[Opening Animation]
|
|
||||||
Opening Scale Punch: 0.5
|
|
||||||
Opening Rotation Punch: 360
|
|
||||||
Opening Duration: 0.5
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Creating in Unity (Step-by-Step)
|
|
||||||
|
|
||||||
### **Step 1: Create Root GameObject**
|
|
||||||
1. Right-click in Hierarchy → UI → Image
|
|
||||||
2. Name it: `BoosterPackPrefab`
|
|
||||||
3. Set Size: 200x300 (Width x Height)
|
|
||||||
4. Add sprite: Temporary placeholder or your booster sprite
|
|
||||||
5. **IMPORTANT:** Ensure `raycastTarget` is ✓ checked
|
|
||||||
|
|
||||||
### **Step 2: Add BoosterPackDraggable**
|
|
||||||
1. Add Component → `BoosterPackDraggable`
|
|
||||||
2. Configure settings (see above)
|
|
||||||
3. Leave Visual Prefab empty for now
|
|
||||||
|
|
||||||
### **Step 3: Create Visual Child**
|
|
||||||
1. Right-click BoosterPackPrefab → Create Empty
|
|
||||||
2. Name it: `BoosterVisual`
|
|
||||||
3. Add Component → `Canvas`
|
|
||||||
4. Add Component → `Canvas Group`
|
|
||||||
5. Add Component → `BoosterPackVisual`
|
|
||||||
|
|
||||||
### **Step 4: Create TiltParent**
|
|
||||||
1. Right-click BoosterVisual → Create Empty
|
|
||||||
2. Name it: `TiltParent`
|
|
||||||
3. Position: (0, 0, 0)
|
|
||||||
|
|
||||||
### **Step 5: Add Images under TiltParent**
|
|
||||||
1. Right-click TiltParent → UI → Image
|
|
||||||
2. Name it: `PackImage`
|
|
||||||
3. Assign your booster sprite
|
|
||||||
4. **Set raycastTarget to ☐ UNCHECKED**
|
|
||||||
5. Size: 180x280 (slightly smaller)
|
|
||||||
|
|
||||||
### **Step 6: Create ShakeParent**
|
|
||||||
1. Right-click BoosterVisual → Create Empty
|
|
||||||
2. Name it: `ShakeParent`
|
|
||||||
3. Position: (0, 0, 0)
|
|
||||||
|
|
||||||
### **Step 7: Add Glow Effect (Optional)**
|
|
||||||
1. Right-click BoosterVisual → Effects → Particle System
|
|
||||||
2. Name it: `GlowEffect`
|
|
||||||
3. Configure:
|
|
||||||
- Duration: 1
|
|
||||||
- Looping: ✓
|
|
||||||
- Start Lifetime: 1-2
|
|
||||||
- Start Speed: 0
|
|
||||||
- Start Size: 5-10
|
|
||||||
- Start Color: Gold/Yellow with alpha
|
|
||||||
- Shape: Circle, Radius: 1
|
|
||||||
- Emission: Rate over Time = 15
|
|
||||||
- Renderer: Material = Default Particle, Sort Order = 1
|
|
||||||
|
|
||||||
### **Step 8: Wire Up References**
|
|
||||||
1. Select `BoosterVisual`
|
|
||||||
2. In BoosterPackVisual component:
|
|
||||||
- Tilt Parent: Drag `TiltParent`
|
|
||||||
- Shake Parent: Drag `ShakeParent`
|
|
||||||
- Pack Image: Drag `PackImage`
|
|
||||||
- Pack Sprite: Assign sprite asset
|
|
||||||
- Glow Effect: Drag `GlowEffect` (if using)
|
|
||||||
|
|
||||||
### **Step 9: Make Prefab**
|
|
||||||
1. Drag `BoosterPackPrefab` to Project folder
|
|
||||||
2. Delete from scene
|
|
||||||
3. You now have a reusable prefab!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Instantiation in Scene
|
|
||||||
|
|
||||||
### **Option A: Prefab Instances (Recommended)**
|
|
||||||
In your BoosterOpeningPage scene:
|
|
||||||
1. Create empty GameObject: `BoosterInstances`
|
|
||||||
2. Drag 3 instances of your prefab into it
|
|
||||||
3. Name them: `BoosterPack_0`, `BoosterPack_1`, `BoosterPack_2`
|
|
||||||
4. Set all to Active = ☐ (unchecked)
|
|
||||||
5. Position doesn't matter - they'll be assigned to slots
|
|
||||||
|
|
||||||
### **Option B: Runtime Instantiation**
|
|
||||||
- Assign the prefab to BoosterOpeningPage
|
|
||||||
- Script will instantiate as needed
|
|
||||||
- (Not implemented yet, but easy to add)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧪 Testing Your Prefab
|
|
||||||
|
|
||||||
### **Test 1: Visual Check**
|
|
||||||
1. Place one instance in scene (active)
|
|
||||||
2. Enter Play Mode
|
|
||||||
3. Should see: Sprite, idle wobble animation
|
|
||||||
4. Hover over it: Should scale up slightly
|
|
||||||
|
|
||||||
### **Test 2: Drag Test**
|
|
||||||
1. Create a SlotContainer with a slot
|
|
||||||
2. Try dragging the booster to the slot
|
|
||||||
3. Should snap smoothly
|
|
||||||
4. Visual should lerp-follow with delay
|
|
||||||
|
|
||||||
### **Test 3: Tap Test**
|
|
||||||
1. Place booster in a slot
|
|
||||||
2. Set Can Tap To Open = ✓, Max Taps = 3
|
|
||||||
3. Click 3 times
|
|
||||||
4. Should see increasing shakes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📐 Size Recommendations
|
|
||||||
|
|
||||||
### **For Mobile:**
|
|
||||||
- Booster: 200x300
|
|
||||||
- Center Slot Scale: 2x → 400x600
|
|
||||||
- Card: 180x250
|
|
||||||
|
|
||||||
### **For Desktop:**
|
|
||||||
- Booster: 250x350
|
|
||||||
- Center Slot Scale: 1.5x → 375x525
|
|
||||||
- Card: 200x280
|
|
||||||
|
|
||||||
### **Spacing:**
|
|
||||||
- Bottom slots: 120-150 units apart
|
|
||||||
- Cards: 150-200 units apart
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Sprite Requirements
|
|
||||||
|
|
||||||
### **Booster Pack Sprite:**
|
|
||||||
- Recommended: 512x768 or 1024x1536
|
|
||||||
- Format: PNG with transparency
|
|
||||||
- Style: Vertical rectangle (2:3 ratio)
|
|
||||||
- Should have clear visual identity
|
|
||||||
|
|
||||||
### **Card Back Sprite:**
|
|
||||||
- Same aspect ratio as cards
|
|
||||||
- Clearly distinct from front
|
|
||||||
- Can match booster theme
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Troubleshooting Prefabs
|
|
||||||
|
|
||||||
**Problem: Can't click/drag booster**
|
|
||||||
→ Check: Root Image has raycastTarget = ✓
|
|
||||||
→ Check: Visual children have raycastTarget = ☐
|
|
||||||
|
|
||||||
**Problem: Visual doesn't follow smoothly**
|
|
||||||
→ Check: BoosterPackVisual is initialized
|
|
||||||
→ Check: Follow Speed > 0, Use Follow Delay = ✓
|
|
||||||
|
|
||||||
**Problem: No shake animation**
|
|
||||||
→ Check: BoosterPackVisual subscribes to OnTapped
|
|
||||||
→ Check: TiltParent and ShakeParent are assigned
|
|
||||||
|
|
||||||
**Problem: Booster looks weird when dragging**
|
|
||||||
→ Check: TiltParent contains the images
|
|
||||||
→ Check: Rotation parameters are reasonable (10-30)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 Advanced Customization
|
|
||||||
|
|
||||||
### **Rarity-Based Visuals:**
|
|
||||||
Add different sprites or effects based on rarity:
|
|
||||||
```csharp
|
|
||||||
// In BoosterPackDraggable or Visual:
|
|
||||||
public enum BoosterRarity { Common, Rare, Legendary }
|
|
||||||
public BoosterRarity rarity;
|
|
||||||
|
|
||||||
// Change sprite/effects based on rarity
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Opening Sequence:**
|
|
||||||
Customize the opening animation:
|
|
||||||
- Adjust Opening Scale Punch (0.5 default)
|
|
||||||
- Adjust Opening Rotation Punch (360 default)
|
|
||||||
- Add sound effects in `PlayOpeningAnimation()`
|
|
||||||
|
|
||||||
### **Hover Effects:**
|
|
||||||
Make boosters more responsive:
|
|
||||||
- Increase Scale On Hover (1.15 → 1.3)
|
|
||||||
- Add glow intensity on hover
|
|
||||||
- Tilt toward mouse more (Manual Tilt Amount)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Final Checklist
|
|
||||||
|
|
||||||
Before using your prefab:
|
|
||||||
- [ ] Root has BoosterPackDraggable
|
|
||||||
- [ ] Root Image has raycastTarget = TRUE
|
|
||||||
- [ ] Visual child has BoosterPackVisual
|
|
||||||
- [ ] TiltParent exists and contains sprites
|
|
||||||
- [ ] ShakeParent exists
|
|
||||||
- [ ] All image children have raycastTarget = FALSE
|
|
||||||
- [ ] References are wired up in Visual
|
|
||||||
- [ ] Prefab is saved in Project
|
|
||||||
- [ ] Can Tap To Open = ✓
|
|
||||||
- [ ] Max Taps To Open = 3 (or your choice)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
🎉 **You're ready to create beautiful, interactive booster packs!** 🎉
|
|
||||||
|
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
# Apple Hills Card System – Designer Playbook
|
|
||||||
|
|
||||||
This playbook is for designers working with the rarity‑based Card System in Apple Hills. It provides a high‑level architecture overview, fast TL;DR playbooks for common tasks (with code-first snippets), and deeper guidance on how the system fits together.
|
|
||||||
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
- [Architecture at a Glance](#architecture-at-a-glance)
|
|
||||||
- [TL;DR Playbooks (Code-First)](#tldr-playbooks-code-first)
|
|
||||||
- [Open Booster Packs](#open-booster-packs)
|
|
||||||
- [Grant a Specific Card](#grant-a-specific-card)
|
|
||||||
- [Query the Collection](#query-the-collection)
|
|
||||||
- [Configure Visuals by Code (optional)](#configure-visuals-by-code-optional)
|
|
||||||
- [Clear the Collection](#clear-the-collection)
|
|
||||||
- [Authoring with the Card Editor (No Manual Setup)](#authoring-with-the-card-editor-no-manual-setup)
|
|
||||||
- [What happens automatically (under the hood)](#what-happens-automatically-under-the-hood)
|
|
||||||
- [In-Depth Overview](#in-depth-overview)
|
|
||||||
- [Designer How‑Tos (Quick Reference)](#designer-how-tos-quick-reference)
|
|
||||||
- [Best Practices & Tips](#best-practices--tips)
|
|
||||||
- [Known Gaps](#known-gaps)
|
|
||||||
- [FAQ](#faq)
|
|
||||||
- [Technical Reference (Quick)](#technical-reference-quick)
|
|
||||||
- [Change Log](#change-log)
|
|
||||||
|
|
||||||
|
|
||||||
## Architecture at a Glance
|
|
||||||
|
|
||||||
The system is split into two main layers with clear responsibilities and a lightweight event bridge.
|
|
||||||
|
|
||||||
- Data Layer (`Assets/Scripts/Data/CardSystem`)
|
|
||||||
- `CardSystemManager` (singleton)
|
|
||||||
- Source of truth for all card definitions, booster logic, and player `CardInventory`.
|
|
||||||
- Emits events on collection changes and booster activity.
|
|
||||||
- `CardInventory`
|
|
||||||
- Player’s owned cards and booster pack counters.
|
|
||||||
- Utility APIs for filtering cards (by rarity, zone, etc.).
|
|
||||||
- `CardDefinition` (`ScriptableObject`)
|
|
||||||
- Authoring asset that defines a card (name, visuals, zone, rarity tiering).
|
|
||||||
- `CardData`
|
|
||||||
- Runtime instance of a card in the player collection (ID, rarity, copies owned, links back to `CardDefinition`).
|
|
||||||
- `CardVisualConfig` (`ScriptableObject`)
|
|
||||||
- Central mapping for rarity/zone → visual treatment (colors, frames, shapes).
|
|
||||||
|
|
||||||
- UI Layer (`Assets/Scripts/UI/CardSystem`)
|
|
||||||
- `CardAlbumUI`
|
|
||||||
- Entry point for the card UI (menu, album browser, booster opening).
|
|
||||||
- `UIPageController` + `UIPage`
|
|
||||||
- Stack-based navigation (push/pop) and shared transitions.
|
|
||||||
- Page Components
|
|
||||||
- `CardMenuPage` – Card hub/menu
|
|
||||||
- `AlbumViewPage` – Grid album view with filter/sort options
|
|
||||||
- `BoosterOpeningPage` – Interactive three-card reveal
|
|
||||||
- `CardUIElement`
|
|
||||||
- Renders a single card using `CardData` and `CardVisualConfig`
|
|
||||||
- `BoosterNotificationDot`
|
|
||||||
- Shows available booster pack count
|
|
||||||
|
|
||||||
- Events (Data ↔ UI)
|
|
||||||
- `OnBoosterCountChanged`
|
|
||||||
- `OnBoosterOpened`
|
|
||||||
- `OnCardCollected`
|
|
||||||
- `OnCardRarityUpgraded`
|
|
||||||
|
|
||||||
- Lifecycle
|
|
||||||
- Initialize during boot: `BootCompletionService.RegisterInitAction(...)`
|
|
||||||
- `CardSystemManager.Instance` is the access point from UI and tools (e.g., `CardSystemTester`)
|
|
||||||
|
|
||||||
|
|
||||||
## TL;DR Playbooks (Code-First)
|
|
||||||
|
|
||||||
These are the most common tasks you’ll perform in code. Paste the snippets into a temporary test `MonoBehaviour`, a unit test, or hook them into your gameplay systems.
|
|
||||||
|
|
||||||
### Open Booster Packs
|
|
||||||
```csharp
|
|
||||||
using AppleHills.Data.CardSystem;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public class BoosterOpenerSample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
// Subscribe to events (optional, for feedback/UI updates)
|
|
||||||
CardSystemManager.Instance.OnBoosterOpened += cards =>
|
|
||||||
{
|
|
||||||
Debug.Log($"Opened booster with {cards.Count} cards");
|
|
||||||
};
|
|
||||||
CardSystemManager.Instance.OnCardCollected += card =>
|
|
||||||
{
|
|
||||||
Debug.Log($"Collected: {card.Definition.Name} (rarity: {card.Rarity})");
|
|
||||||
};
|
|
||||||
CardSystemManager.Instance.OnCardRarityUpgraded += card =>
|
|
||||||
{
|
|
||||||
Debug.Log($"Upgraded rarity: {card.Definition.Name} -> {card.Rarity}");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Give the player some boosters and open one
|
|
||||||
CardSystemManager.Instance.AddBoosterPack(1);
|
|
||||||
var revealed = CardSystemManager.Instance.OpenBoosterPack();
|
|
||||||
foreach (var cd in revealed)
|
|
||||||
{
|
|
||||||
Debug.Log($"Revealed: {cd.Definition.Name}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Grant a Specific Card
|
|
||||||
```csharp
|
|
||||||
using System.Linq;
|
|
||||||
using AppleHills.Data.CardSystem;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public class GrantCardSample : MonoBehaviour
|
|
||||||
{
|
|
||||||
[SerializeField] private string cardName = "Apple Picker"; // example
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
var def = CardSystemManager.Instance
|
|
||||||
.GetAllCardDefinitions()
|
|
||||||
.FirstOrDefault(d => d.Name == cardName);
|
|
||||||
if (def == null)
|
|
||||||
{
|
|
||||||
Debug.LogWarning($"CardDefinition not found: {cardName}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var cardData = CardSystemManager.Instance.AddCardToInventory(def);
|
|
||||||
Debug.Log($"Granted: {cardData.Definition.Name} (copies: {cardData.CopiesOwned})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Query the Collection
|
|
||||||
```csharp
|
|
||||||
using AppleHills.Data.CardSystem;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public class QueryCollectionSample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
var inv = CardSystemManager.Instance.GetCardInventory();
|
|
||||||
|
|
||||||
// All cards
|
|
||||||
var all = inv.GetAllCards();
|
|
||||||
Debug.Log($"Total cards owned: {all.Count}");
|
|
||||||
|
|
||||||
// By rarity (example)
|
|
||||||
var rares = inv.GetByRarity(CardRarity.Rare);
|
|
||||||
Debug.Log($"Rares: {rares.Count}");
|
|
||||||
|
|
||||||
// By zone (example)
|
|
||||||
var forest = inv.GetByZone(CardZone.Forest);
|
|
||||||
Debug.Log($"Forest: {forest.Count}");
|
|
||||||
|
|
||||||
// Counts (progression checks)
|
|
||||||
var byRarity = inv.CountByRarity();
|
|
||||||
var byZone = inv.CountByZone();
|
|
||||||
// Iterate dictionaries as needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Clear the Collection
|
|
||||||
```csharp
|
|
||||||
using AppleHills.Data.CardSystem;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public class ClearCollectionSample : MonoBehaviour
|
|
||||||
{
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
CardSystemManager.Instance.ClearAllCards();
|
|
||||||
Debug.Log("Card collection cleared (dev/test only).");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Authoring with the Card Editor (No Manual Setup)
|
|
||||||
Designers should use the dedicated editor window: `AppleHills/Card Editor`.
|
|
||||||
|
|
||||||
- Open via Unity menu: `AppleHills/Card Editor` (menu path defined in `CardEditorWindow`)
|
|
||||||
- The window provides a card list, detail editor, and a live preview of the UI card.
|
|
||||||
- You don’t need to create folders or assets manually—the tool handles setup and discovery.
|
|
||||||
|
|
||||||
### What happens automatically (under the hood)
|
|
||||||
The `Assets/Editor/CardSystem/CardEditorWindow.cs` implements the following behaviors:
|
|
||||||
- Ensures the data directory exists: `Assets/Data/Cards` (creates it on first run).
|
|
||||||
- Discovers all `CardDefinition` assets under `Assets/Data/Cards` automatically via `AssetDatabase.FindAssets("t:CardDefinition")` and keeps the list sorted by `Name`.
|
|
||||||
- Creates new card assets as `Card_<Name>.asset` inside `Assets/Data/Cards`.
|
|
||||||
- Loads a UI preview prefab from `Assets/Prefabs/UI/Cards/SIngleCardDisplayUI.prefab` to render a live card preview inside the editor using `PreviewRenderUtility`.
|
|
||||||
- Tries to load `CardVisualConfig` at `Assets/Data/Cards/CardVisualConfig.asset` for consistent rarity/zone styling in the preview.
|
|
||||||
- Responds to Undo/Redo and Editor recompiles to stay in sync.
|
|
||||||
- When you duplicate or delete cards from the window, the corresponding assets are created/removed accordingly.
|
|
||||||
|
|
||||||
Result: Designers focus on content (name, description, zone, art, etc.) in the Card Editor. The system takes care of folders, discovery, previewing, and syncing definitions with runtime.
|
|
||||||
|
|
||||||
|
|
||||||
## In-Depth Overview
|
|
||||||
|
|
||||||
Data Layer Details
|
|
||||||
- `CardDefinition` (authoring)
|
|
||||||
- What it is: a `ScriptableObject` that defines a card’s identity and static presentation (name, description, zone, default visuals).
|
|
||||||
- Typical fields: `Name`, `Description`, `Zone`, rarity metadata, sprites/textures, optional tags.
|
|
||||||
- Helpers: `CreateCardData()` to generate a runtime `CardData` instance for inventory.
|
|
||||||
|
|
||||||
- `CardData` (runtime instance)
|
|
||||||
- Purpose: Represents what the player owns – unique ID, rarity state, copies owned.
|
|
||||||
- Behavior: When duplicates are collected, `CardData` may upgrade rarity (e.g., duplicate thresholds).
|
|
||||||
- Links: Holds reference to its `CardDefinition` for display and classification.
|
|
||||||
|
|
||||||
- `CardInventory` (player collection)
|
|
||||||
- Responsibilities: Store cards, track counts, support filters/lookups (by rarity/zone), manage booster counters.
|
|
||||||
- Common operations: `AddCard(def)`, `GetAllCards()`, `GetByRarity()`, `GetByZone()`, `CountByRarity()`, `CountByZone()`.
|
|
||||||
- Notes: Designed for efficiency and clarity; returns collections for the UI to display.
|
|
||||||
|
|
||||||
- `CardSystemManager` (singleton coordinator)
|
|
||||||
- Responsibilities: Owns `CardInventory`, holds the card definition catalog, controls booster generation/opening, exposes public APIs.
|
|
||||||
- Events: `OnBoosterCountChanged`, `OnBoosterOpened`, `OnCardCollected`, `OnCardRarityUpgraded`.
|
|
||||||
- Typical APIs:
|
|
||||||
- `GetAllCardDefinitions()` → `IReadOnlyList<CardDefinition>`
|
|
||||||
- `GetCardInventory()` → `CardInventory`
|
|
||||||
- `AddBoosterPack(int count)`
|
|
||||||
- `OpenBoosterPack()` → `List<CardData>` (or similar)
|
|
||||||
- `AddCardToInventory(CardDefinition def)`
|
|
||||||
- `ClearAllCards()`
|
|
||||||
|
|
||||||
- `CardVisualConfig` (visual mappings)
|
|
||||||
- Purpose: Central place to establish the brand/look per rarity and zone.
|
|
||||||
- Implementation: `ScriptableObject` with dictionaries for quick lookups by rarity/zone.
|
|
||||||
|
|
||||||
UI Layer Details
|
|
||||||
- `UIPageController` + `UIPage`
|
|
||||||
- Navigation: `PushPage(page)`, `PopPage()`, `Clear()`; optional transition animations.
|
|
||||||
- Pattern: Each page is a `UIPage` subclass registered under `CardAlbumUI`.
|
|
||||||
|
|
||||||
- `CardAlbumUI` (system entry)
|
|
||||||
- Role: Wires pages together, responds to `CardSystemManager` events, routes to `AlbumViewPage` or `BoosterOpeningPage`.
|
|
||||||
|
|
||||||
- `AlbumViewPage`
|
|
||||||
- Role: Displays a grid of `CardUIElement` items from `CardInventory` with filtering/sorting UI.
|
|
||||||
- Notes: Uses TextMeshPro components and simplified presentation (no stack/slot system).
|
|
||||||
|
|
||||||
- `BoosterOpeningPage`
|
|
||||||
- Role: Handles the interactive reveal flow for 3 cards per booster; flip animations, particle FX, rarity feedback.
|
|
||||||
- Notes: Timings and art are still under refinement; supports individual reveal clicks.
|
|
||||||
|
|
||||||
- `CardUIElement`
|
|
||||||
- Role: Displays a single `CardData` – name, art, frame, rarity chips, zone styling.
|
|
||||||
- Data Source: Uses `CardVisualConfig` for color/frame mapping.
|
|
||||||
|
|
||||||
- `BoosterNotificationDot`
|
|
||||||
- Role: Indicates current booster count; listens to `OnBoosterCountChanged`.
|
|
||||||
|
|
||||||
Event Flow Examples
|
|
||||||
- Opening a booster
|
|
||||||
- Player code calls `CardSystemManager.OpenBoosterPack()` → generates/awards 3 cards → raises `OnBoosterOpened`.
|
|
||||||
- Inventory updated; for each card, `OnCardCollected` (and maybe `OnCardRarityUpgraded`) fires.
|
|
||||||
- `BoosterOpeningPage` animates reveals; `AlbumViewPage` updates when returning.
|
|
||||||
|
|
||||||
- Adding a card via quest reward
|
|
||||||
- Gameplay script calls `AddCardToInventory(def)`.
|
|
||||||
- Inventory updates; events fire to update UI.
|
|
||||||
|
|
||||||
Rarity & Duplicates
|
|
||||||
- The system tracks copies owned per card.
|
|
||||||
- Duplicates can trigger rarity upgrades based on thresholds (implemented in `CardData`).
|
|
||||||
- UI can react with special effects via `OnCardRarityUpgraded` (e.g., distinct VFX/SFX per rarity).
|
|
||||||
|
|
||||||
|
|
||||||
## Designer How‑Tos (Quick Reference)
|
|
||||||
|
|
||||||
Author a New Card (use the editor tool)
|
|
||||||
1) Open `AppleHills/Card Editor`.
|
|
||||||
2) Click New/Duplicate, edit `Name`, `Description`, `Zone`, and assign art.
|
|
||||||
3) Save—asset is created as `Assets/Data/Cards/Card_<Name>.asset`. It’s auto-discovered by runtime.
|
|
||||||
|
|
||||||
Grant a Card by Code (quest reward)
|
|
||||||
```csharp
|
|
||||||
CardSystemManager.Instance.AddCardToInventory(rewardDefinition);
|
|
||||||
```
|
|
||||||
|
|
||||||
Open a Booster by Code
|
|
||||||
```csharp
|
|
||||||
CardSystemManager.Instance.AddBoosterPack(1);
|
|
||||||
CardSystemManager.Instance.OpenBoosterPack();
|
|
||||||
```
|
|
||||||
|
|
||||||
Filter Cards for a Page
|
|
||||||
```csharp
|
|
||||||
var inv = CardSystemManager.Instance.GetCardInventory();
|
|
||||||
var list = inv.GetByZone(CardZone.Quarry);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Best Practices & Tips
|
|
||||||
|
|
||||||
- Always access data via `CardSystemManager.Instance` to keep a single source of truth.
|
|
||||||
- Keep `CardDefinition` assets lightweight and consistent; use tags/zones for filtering.
|
|
||||||
- When adding new rarities/zones, update `CardVisualConfig` and verify UI styling.
|
|
||||||
- For smoother reveals, coordinate with VFX/SFX to differentiate rarities.
|
|
||||||
- Large collections: consider paging or virtualized grids if performance becomes a concern.
|
|
||||||
|
|
||||||
|
|
||||||
## Known Gaps
|
|
||||||
|
|
||||||
- Save/Load not implemented – test sessions won’t persist player collection.
|
|
||||||
- Booster Opening polish (timings/art/audio) is ongoing.
|
|
||||||
- Collection statistics/achievements UI pending.
|
|
||||||
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
- Q: My new `CardDefinition` doesn’t show up in the album.
|
|
||||||
- A: Ensure the asset is in `Assets/Data/Cards` (the editor tool places it there) and that definitions load before UI opens. Check the `CardSystemManager` discovery and your zones/rarities.
|
|
||||||
|
|
||||||
- Q: How do I trigger the card UI from another part of the game?
|
|
||||||
- A: Use `CardAlbumUI`’s public entry points or route through your UI flow to push the relevant page via `UIPageController`.
|
|
||||||
|
|
||||||
- Q: Can I guarantee a specific rarity in a booster for a tutorial?
|
|
||||||
- A: Add a temporary tutorial hook in `CardSystemManager` to override booster generation rules for guided moments, or directly grant specific `CardDefinition`s for the tutorial step.
|
|
||||||
|
|
||||||
- Q: How do duplicates upgrade rarity?
|
|
||||||
- A: The logic lives in `CardData`; when copies cross thresholds, it fires `OnCardRarityUpgraded`. Coordinate with design to set thresholds and with UI to show feedback.
|
|
||||||
|
|
||||||
|
|
||||||
## Technical Reference (Quick)
|
|
||||||
|
|
||||||
- Initialize after boot: `BootCompletionService.RegisterInitAction(InitializePostBoot)`
|
|
||||||
- Data access: `CardSystemManager.Instance`
|
|
||||||
- Navigation: `UIPageController.Instance.PushPage()` / `PopPage()`
|
|
||||||
- Show a card in UI: `CardUIElement.SetupCard(cardData)`
|
|
||||||
- Test harness: `CardSystemTester` (add to scene, link `CardAlbumUI`)
|
|
||||||
|
|
||||||
|
|
||||||
## Change Log
|
|
||||||
|
|
||||||
- v1.1: Added Table of Contents, inline code formatting, code-first TL;DR playbooks, and an authoring section based on `CardEditorWindow`.
|
|
||||||
- v1.0: Initial designer playbook, aligned with Implementation Plan and Integration & Testing Guide.
|
|
||||||
@@ -1,399 +0,0 @@
|
|||||||
# 🎨 SlotContainer Custom Layout Guide
|
|
||||||
|
|
||||||
## 📋 Overview
|
|
||||||
|
|
||||||
The `SlotContainer` has a **Custom** layout mode that's perfect for artistic, hand-authored slot positions! When you select `Custom`, the SlotContainer **doesn't automatically position your slots** - it lets you manually position them however you want.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 How Custom Layout Works
|
|
||||||
|
|
||||||
### **What Happens When Layout = Custom:**
|
|
||||||
|
|
||||||
Looking at the code:
|
|
||||||
```csharp
|
|
||||||
public void UpdateLayout()
|
|
||||||
{
|
|
||||||
if (layoutType == LayoutType.Custom)
|
|
||||||
{
|
|
||||||
OnLayoutChanged?.Invoke(); // Just fires the event
|
|
||||||
return; // Doesn't reposition anything!
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other layouts (Horizontal, Vertical, Grid) reposition slots here...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Point:** Custom layout means **"Don't touch my slot positions!"**
|
|
||||||
|
|
||||||
The SlotContainer still:
|
|
||||||
- ✅ Registers your slots
|
|
||||||
- ✅ Finds closest slot when dragging
|
|
||||||
- ✅ Manages slot occupancy
|
|
||||||
- ✅ Fires events
|
|
||||||
|
|
||||||
But it **does NOT:**
|
|
||||||
- ❌ Automatically position slots
|
|
||||||
- ❌ Apply spacing
|
|
||||||
- ❌ Center slots
|
|
||||||
- ❌ Use curves or grids
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛠️ Setting Up Custom Layout (Step-by-Step)
|
|
||||||
|
|
||||||
### **Method 1: Hand-Author in Scene (Recommended)**
|
|
||||||
|
|
||||||
This is the easiest and most visual approach:
|
|
||||||
|
|
||||||
1. **Create SlotContainer:**
|
|
||||||
```
|
|
||||||
BottomRightContainer
|
|
||||||
└── [Add Component: SlotContainer]
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Set Layout Type:**
|
|
||||||
- Layout Type: `Custom`
|
|
||||||
- Auto Register Children: ✓ (keep this checked)
|
|
||||||
|
|
||||||
3. **Create Slot Children:**
|
|
||||||
```
|
|
||||||
BottomRightContainer
|
|
||||||
├── Slot_0 (DraggableSlot)
|
|
||||||
├── Slot_1 (DraggableSlot)
|
|
||||||
├── Slot_2 (DraggableSlot)
|
|
||||||
└── Slot_3 (DraggableSlot)
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Position Slots Manually in Scene View:**
|
|
||||||
- Select `Slot_0`
|
|
||||||
- Drag it to artistic position (e.g., X=-150, Y=200)
|
|
||||||
- Select `Slot_1`
|
|
||||||
- Drag it to artistic position (e.g., X=50, Y=150)
|
|
||||||
- Select `Slot_2`
|
|
||||||
- Drag it to artistic position (e.g., X=-200, Y=50)
|
|
||||||
- Etc.
|
|
||||||
|
|
||||||
5. **Done!** Your slots stay exactly where you put them.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Method 2: Script Positions (For Procedural Scatter)**
|
|
||||||
|
|
||||||
If you want some randomness or code-controlled positions:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using UnityEngine;
|
|
||||||
using UI.DragAndDrop.Core;
|
|
||||||
|
|
||||||
public class CustomSlotPositioner : MonoBehaviour
|
|
||||||
{
|
|
||||||
[SerializeField] private SlotContainer slotContainer;
|
|
||||||
[SerializeField] private Vector2[] handAuthoredPositions;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
PositionSlots();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PositionSlots()
|
|
||||||
{
|
|
||||||
var slots = slotContainer.Slots;
|
|
||||||
|
|
||||||
for (int i = 0; i < slots.Count && i < handAuthoredPositions.Length; i++)
|
|
||||||
{
|
|
||||||
if (slots[i].RectTransform != null)
|
|
||||||
{
|
|
||||||
slots[i].RectTransform.anchoredPosition = handAuthoredPositions[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then in Inspector:
|
|
||||||
- Hand Authored Positions (Array):
|
|
||||||
- Element 0: (-150, 200)
|
|
||||||
- Element 1: (50, 150)
|
|
||||||
- Element 2: (-200, 50)
|
|
||||||
- Etc.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Method 3: Subscribe to OnLayoutChanged Event**
|
|
||||||
|
|
||||||
For advanced custom positioning logic:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using UnityEngine;
|
|
||||||
using UI.DragAndDrop.Core;
|
|
||||||
|
|
||||||
public class ArtisticSlotLayout : MonoBehaviour
|
|
||||||
{
|
|
||||||
[SerializeField] private SlotContainer slotContainer;
|
|
||||||
[SerializeField] private float scatterRadius = 200f;
|
|
||||||
[SerializeField] private bool useRandomSeed = true;
|
|
||||||
[SerializeField] private int seed = 42;
|
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
if (slotContainer != null)
|
|
||||||
{
|
|
||||||
slotContainer.OnLayoutChanged += ApplyCustomLayout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
if (slotContainer != null)
|
|
||||||
{
|
|
||||||
slotContainer.OnLayoutChanged -= ApplyCustomLayout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyCustomLayout()
|
|
||||||
{
|
|
||||||
if (useRandomSeed)
|
|
||||||
Random.InitState(seed);
|
|
||||||
|
|
||||||
var slots = slotContainer.Slots;
|
|
||||||
|
|
||||||
for (int i = 0; i < slots.Count; i++)
|
|
||||||
{
|
|
||||||
if (slots[i].RectTransform != null)
|
|
||||||
{
|
|
||||||
// Scattered circular layout
|
|
||||||
float angle = Random.Range(0f, 360f);
|
|
||||||
float distance = Random.Range(0f, scatterRadius);
|
|
||||||
|
|
||||||
float x = Mathf.Cos(angle * Mathf.Deg2Rad) * distance;
|
|
||||||
float y = Mathf.Sin(angle * Mathf.Deg2Rad) * distance;
|
|
||||||
|
|
||||||
slots[i].RectTransform.anchoredPosition = new Vector2(x, y);
|
|
||||||
|
|
||||||
// Optional: Random rotation for extra artistic flair
|
|
||||||
slots[i].RectTransform.rotation = Quaternion.Euler(0, 0, Random.Range(-15f, 15f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Example: Artistic Scattered Boosters
|
|
||||||
|
|
||||||
### **Scenario:** 3 booster slots scattered artistically in bottom-right
|
|
||||||
|
|
||||||
**Setup:**
|
|
||||||
```
|
|
||||||
BottomRightContainer (SlotContainer - Custom Layout)
|
|
||||||
├── Slot_0 (DraggableSlot)
|
|
||||||
│ └── Position: (-180, 220)
|
|
||||||
│ └── Rotation: (0, 0, -5) ← Slight tilt left
|
|
||||||
├── Slot_1 (DraggableSlot)
|
|
||||||
│ └── Position: (40, 180)
|
|
||||||
│ └── Rotation: (0, 0, 8) ← Slight tilt right
|
|
||||||
└── Slot_2 (DraggableSlot)
|
|
||||||
└── Position: (-220, 80)
|
|
||||||
└── Rotation: (0, 0, -3) ← Slight tilt left
|
|
||||||
```
|
|
||||||
|
|
||||||
**Visual Result:**
|
|
||||||
```
|
|
||||||
[Slot_0] ← Tilted left, higher
|
|
||||||
[Slot_1] ← Tilted right, middle
|
|
||||||
[Slot_2] ← Tilted left, lower
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚙️ Custom Layout Inspector Settings
|
|
||||||
|
|
||||||
When you select **Custom** layout type, these settings are **ignored**:
|
|
||||||
|
|
||||||
- ❌ Spacing (not used)
|
|
||||||
- ❌ Center Slots (not used)
|
|
||||||
- ❌ Use Curve Layout (not used)
|
|
||||||
- ❌ Position Curve (not used)
|
|
||||||
- ❌ Curve Height (not used)
|
|
||||||
|
|
||||||
These settings **still work**:
|
|
||||||
|
|
||||||
- ✅ Auto Register Children (still registers your slots)
|
|
||||||
- ✅ OnSlotAdded/OnSlotRemoved events (still fire)
|
|
||||||
- ✅ OnLayoutChanged event (fires when UpdateLayout is called)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Best Practices for Custom Layout
|
|
||||||
|
|
||||||
### **1. Use Scene View for Positioning**
|
|
||||||
- Easiest and most visual
|
|
||||||
- See results immediately
|
|
||||||
- Adjust in real-time
|
|
||||||
|
|
||||||
### **2. Add Visual Guides**
|
|
||||||
- Create a background image showing your intended layout
|
|
||||||
- Position slots over the image
|
|
||||||
- Delete/hide the guide after
|
|
||||||
|
|
||||||
### **3. Use Gizmos for Visualization**
|
|
||||||
```csharp
|
|
||||||
private void OnDrawGizmos()
|
|
||||||
{
|
|
||||||
if (slotContainer == null || slotContainer.Slots == null) return;
|
|
||||||
|
|
||||||
Gizmos.color = Color.yellow;
|
|
||||||
|
|
||||||
foreach (var slot in slotContainer.Slots)
|
|
||||||
{
|
|
||||||
if (slot != null)
|
|
||||||
{
|
|
||||||
Gizmos.DrawWireSphere(slot.transform.position, 50f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### **4. Consider Spacing**
|
|
||||||
- Even with artistic scatter, avoid overlapping slots
|
|
||||||
- Leave enough space for hover/selection effects
|
|
||||||
- Test with different screen sizes
|
|
||||||
|
|
||||||
### **5. Save Positions in Prefab**
|
|
||||||
- Once you're happy with positions, save to prefab
|
|
||||||
- Ensures consistency across scenes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔄 Combining Custom with Other Layouts
|
|
||||||
|
|
||||||
You can switch layout types at runtime:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class DynamicLayoutSwitcher : MonoBehaviour
|
|
||||||
{
|
|
||||||
[SerializeField] private SlotContainer slotContainer;
|
|
||||||
|
|
||||||
public void SwitchToScattered()
|
|
||||||
{
|
|
||||||
// Save current positions
|
|
||||||
Vector2[] savedPositions = new Vector2[slotContainer.SlotCount];
|
|
||||||
for (int i = 0; i < slotContainer.SlotCount; i++)
|
|
||||||
{
|
|
||||||
savedPositions[i] = slotContainer.GetSlotAtIndex(i).RectTransform.anchoredPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch to custom
|
|
||||||
// Note: You'd need to expose layoutType or use reflection
|
|
||||||
// For now, this is just conceptual
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 Quick Setup Checklist
|
|
||||||
|
|
||||||
For your bottom-right booster slots:
|
|
||||||
|
|
||||||
1. **Create Container:**
|
|
||||||
```
|
|
||||||
BottomRightContainer
|
|
||||||
└── Layout Type: Custom
|
|
||||||
└── Auto Register Children: ✓
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Create 3 Slot Children:**
|
|
||||||
```
|
|
||||||
Slot_0, Slot_1, Slot_2
|
|
||||||
└── Each has DraggableSlot component
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Position Each Slot:**
|
|
||||||
- Use Scene View
|
|
||||||
- Click and drag to artistic positions
|
|
||||||
- Optional: Add slight rotation (Z-axis)
|
|
||||||
|
|
||||||
4. **Test:**
|
|
||||||
- Drag boosters to slots
|
|
||||||
- Verify they snap correctly
|
|
||||||
- Adjust positions as needed
|
|
||||||
|
|
||||||
5. **Save to Prefab:**
|
|
||||||
- Once happy, save BoosterOpeningPage prefab
|
|
||||||
- Positions are preserved
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 Creative Ideas
|
|
||||||
|
|
||||||
### **Scattered Stack:**
|
|
||||||
```
|
|
||||||
Slot_0: (-200, 250) Rotation: -8°
|
|
||||||
Slot_1: (-180, 220) Rotation: 3°
|
|
||||||
Slot_2: (-210, 195) Rotation: -5°
|
|
||||||
```
|
|
||||||
→ Looks like a messy pile of cards!
|
|
||||||
|
|
||||||
### **Arc Formation:**
|
|
||||||
```
|
|
||||||
Slot_0: (-180, 200) Rotation: -15°
|
|
||||||
Slot_1: (0, 220) Rotation: 0°
|
|
||||||
Slot_2: (180, 200) Rotation: 15°
|
|
||||||
```
|
|
||||||
→ Gentle arc, like cards in hand
|
|
||||||
|
|
||||||
### **Diagonal Cascade:**
|
|
||||||
```
|
|
||||||
Slot_0: (-150, 250) Rotation: -10°
|
|
||||||
Slot_1: (-50, 180) Rotation: -5°
|
|
||||||
Slot_2: (50, 110) Rotation: 0°
|
|
||||||
```
|
|
||||||
→ Diagonal waterfall effect
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐛 Troubleshooting Custom Layout
|
|
||||||
|
|
||||||
**Problem: Slots keep resetting position**
|
|
||||||
→ Make sure Layout Type = `Custom`
|
|
||||||
→ Check if something is calling `UpdateLayout()` with a different type
|
|
||||||
|
|
||||||
**Problem: Slots don't register**
|
|
||||||
→ Ensure Auto Register Children = ✓
|
|
||||||
→ Verify slots are direct children of SlotContainer
|
|
||||||
|
|
||||||
**Problem: Can't drag boosters to slots**
|
|
||||||
→ Check DraggableSlot configuration (Filter By Type, etc.)
|
|
||||||
→ Verify slots aren't locked
|
|
||||||
|
|
||||||
**Problem: Positions lost on scene reload**
|
|
||||||
→ Save to prefab!
|
|
||||||
→ Check if positions are being set in Awake/Start
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Summary
|
|
||||||
|
|
||||||
**Custom Layout = Full Manual Control!**
|
|
||||||
|
|
||||||
- ✅ Position slots anywhere you want
|
|
||||||
- ✅ Add rotation for artistic flair
|
|
||||||
- ✅ No automatic repositioning
|
|
||||||
- ✅ Perfect for hand-authored layouts
|
|
||||||
- ✅ Still gets all SlotContainer benefits (registration, finding, events)
|
|
||||||
|
|
||||||
**Recommended Workflow:**
|
|
||||||
1. Set Layout Type = Custom
|
|
||||||
2. Create slot children
|
|
||||||
3. Position visually in Scene View
|
|
||||||
4. Test drag-and-drop
|
|
||||||
5. Adjust as needed
|
|
||||||
6. Save to prefab
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
🎨 **Now go create some beautiful, artistic slot layouts!** 🎨
|
|
||||||
|
|
||||||
@@ -1,309 +0,0 @@
|
|||||||
# Drag and Drop Card System
|
|
||||||
|
|
||||||
A robust, touch-compatible drag-and-drop system for Unity UI, inspired by Balatro's visual feel. Supports cards, booster packs, and any other draggable objects with smooth visual effects.
|
|
||||||
|
|
||||||
## Architecture Overview
|
|
||||||
|
|
||||||
The system is built on a separation of concerns:
|
|
||||||
- **Logic Layer** (`DraggableObject`) - Handles dragging, slot snapping, events
|
|
||||||
- **Visual Layer** (`DraggableVisual`) - Follows the logic object with lerping, tilting, animations
|
|
||||||
- **Slot System** (`DraggableSlot` + `SlotContainer`) - Manages positions and layout
|
|
||||||
|
|
||||||
## Core Components
|
|
||||||
|
|
||||||
### 1. DraggableObject (Abstract Base Class)
|
|
||||||
Base class for any draggable UI element.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- Touch-compatible via Unity's pointer event system
|
|
||||||
- Smooth movement toward pointer (configurable)
|
|
||||||
- Automatic slot snapping on release
|
|
||||||
- Selection support with visual offset
|
|
||||||
- Comprehensive event system
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```csharp
|
|
||||||
public class MyDraggable : DraggableObject
|
|
||||||
{
|
|
||||||
protected override void OnDragStartedHook()
|
|
||||||
{
|
|
||||||
// Custom logic when drag starts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. DraggableVisual (Abstract Base Class)
|
|
||||||
Visual representation that follows the DraggableObject.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- Lerps toward parent position (not instant)
|
|
||||||
- Tilt based on movement velocity
|
|
||||||
- Auto-tilt idle animation (sine/cosine wobble)
|
|
||||||
- Manual tilt when hovering
|
|
||||||
- Scale animations on hover/drag/select
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```csharp
|
|
||||||
public class MyVisual : DraggableVisual
|
|
||||||
{
|
|
||||||
protected override void UpdateVisualContent()
|
|
||||||
{
|
|
||||||
// Update your visual elements here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. DraggableSlot
|
|
||||||
Represents a position where draggables can snap.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- Occupancy management (one object per slot)
|
|
||||||
- Type filtering (restrict which types can occupy)
|
|
||||||
- Lock/unlock functionality
|
|
||||||
- Swap support
|
|
||||||
|
|
||||||
### 4. SlotContainer
|
|
||||||
Manages a collection of slots.
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- Multiple layout types (Horizontal, Vertical, Grid, Custom)
|
|
||||||
- Curve-based positioning for horizontal layouts
|
|
||||||
- Automatic slot registration
|
|
||||||
- Find closest slot algorithm
|
|
||||||
|
|
||||||
**Layout Types:**
|
|
||||||
- **Horizontal** - Slots arranged in a horizontal line (with optional curve)
|
|
||||||
- **Vertical** - Slots arranged in a vertical line
|
|
||||||
- **Grid** - Slots arranged in a grid pattern
|
|
||||||
- **Custom** - Manually position slots
|
|
||||||
|
|
||||||
## Card-Specific Implementations
|
|
||||||
|
|
||||||
### CardDraggable
|
|
||||||
Card-specific draggable implementation.
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Holds `CardData` reference
|
|
||||||
- Events for card data changes
|
|
||||||
- Integrates with `CardSystemManager`
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
```csharp
|
|
||||||
CardDraggable card = GetComponent<CardDraggable>();
|
|
||||||
card.SetCardData(myCardData);
|
|
||||||
```
|
|
||||||
|
|
||||||
### CardDraggableVisual
|
|
||||||
Visual representation for cards.
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Uses existing `CardDisplay` component
|
|
||||||
- Shadow effects on press
|
|
||||||
- Automatic visual refresh when card data changes
|
|
||||||
|
|
||||||
### BoosterPackDraggable
|
|
||||||
Booster pack implementation.
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Double-click to open support
|
|
||||||
- Opening state management
|
|
||||||
- Events for opening
|
|
||||||
|
|
||||||
### BoosterPackVisual
|
|
||||||
Visual representation for booster packs.
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Glow particle effects
|
|
||||||
- Opening animation (scale + rotation)
|
|
||||||
- Sprite customization
|
|
||||||
|
|
||||||
## Setup Guide
|
|
||||||
|
|
||||||
### Basic Setup
|
|
||||||
|
|
||||||
1. **Create Slot Container:**
|
|
||||||
```
|
|
||||||
GameObject → UI → Panel (rename to "CardSlotContainer")
|
|
||||||
Add Component → SlotContainer
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Create Slots:**
|
|
||||||
```
|
|
||||||
Under CardSlotContainer:
|
|
||||||
GameObject → UI → Empty (rename to "Slot_01")
|
|
||||||
Add Component → DraggableSlot
|
|
||||||
```
|
|
||||||
Duplicate for as many slots as needed.
|
|
||||||
|
|
||||||
3. **Create Draggable Card:**
|
|
||||||
```
|
|
||||||
GameObject → UI → Image (rename to "CardDraggable")
|
|
||||||
Add Component → CardDraggable
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Create Visual Prefab:**
|
|
||||||
```
|
|
||||||
Create a prefab with:
|
|
||||||
- Root: Empty GameObject with CardDraggableVisual component
|
|
||||||
- Child: Canvas (for sorting control)
|
|
||||||
- Child: TiltParent (Transform for tilt effects)
|
|
||||||
- Child: ShakeParent (Transform for punch effects)
|
|
||||||
- Child: CardDisplay (your existing card visual)
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **Link Visual to Draggable:**
|
|
||||||
```
|
|
||||||
On CardDraggable:
|
|
||||||
- Assign your visual prefab to "Visual Prefab"
|
|
||||||
- Set "Instantiate Visual" to true
|
|
||||||
```
|
|
||||||
|
|
||||||
### Advanced: Curved Hand Layout
|
|
||||||
|
|
||||||
For a Balatro-style curved card hand:
|
|
||||||
|
|
||||||
1. On SlotContainer:
|
|
||||||
- Set Layout Type to "Horizontal"
|
|
||||||
- Enable "Use Curve Layout"
|
|
||||||
- Edit "Position Curve" (try: keys at 0,0.5,1 with values 0,1,0)
|
|
||||||
- Set "Curve Height" (e.g., 50)
|
|
||||||
- Enable "Center Slots"
|
|
||||||
|
|
||||||
2. Adjust spacing to fit your card size
|
|
||||||
|
|
||||||
## Event System
|
|
||||||
|
|
||||||
### DraggableObject Events:
|
|
||||||
```csharp
|
|
||||||
draggable.OnDragStarted += (obj) => { };
|
|
||||||
draggable.OnDragEnded += (obj) => { };
|
|
||||||
draggable.OnPointerEntered += (obj) => { };
|
|
||||||
draggable.OnPointerExited += (obj) => { };
|
|
||||||
draggable.OnPointerDowned += (obj) => { };
|
|
||||||
draggable.OnPointerUpped += (obj, longPress) => { };
|
|
||||||
draggable.OnSelected += (obj, selected) => { };
|
|
||||||
draggable.OnSlotChanged += (obj, slot) => { };
|
|
||||||
```
|
|
||||||
|
|
||||||
### CardDraggable Events:
|
|
||||||
```csharp
|
|
||||||
cardDraggable.OnCardDataChanged += (card, data) => { };
|
|
||||||
```
|
|
||||||
|
|
||||||
### BoosterPackDraggable Events:
|
|
||||||
```csharp
|
|
||||||
boosterDraggable.OnBoosterOpened += (pack) => { };
|
|
||||||
```
|
|
||||||
|
|
||||||
## Touch Support
|
|
||||||
|
|
||||||
The system is fully touch-compatible out of the box! Unity's Event System automatically routes touch events through the pointer interfaces.
|
|
||||||
|
|
||||||
**Supported Gestures:**
|
|
||||||
- Single touch drag
|
|
||||||
- Tap to select
|
|
||||||
- Double-tap (on booster packs)
|
|
||||||
- Long press detection
|
|
||||||
|
|
||||||
**Note:** For multi-touch support, the system uses PointerEventData which handles the first touch automatically. Additional touch support can be added by extending the pointer event handlers.
|
|
||||||
|
|
||||||
## Performance Tips
|
|
||||||
|
|
||||||
1. **Disable Idle Animations** if you have many cards:
|
|
||||||
```
|
|
||||||
On DraggableVisual: useIdleAnimation = false
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Reduce Follow Speed** for smoother performance:
|
|
||||||
```
|
|
||||||
On DraggableVisual: followSpeed = 20 (default: 30)
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Disable Scale Animations** if needed:
|
|
||||||
```
|
|
||||||
On DraggableVisual: useScaleAnimations = false
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Use Object Pooling** for spawning many cards
|
|
||||||
|
|
||||||
## Extending the System
|
|
||||||
|
|
||||||
### Creating Custom Draggable Types
|
|
||||||
|
|
||||||
1. Inherit from `DraggableObject`:
|
|
||||||
```csharp
|
|
||||||
public class MyCustomDraggable : DraggableObject
|
|
||||||
{
|
|
||||||
protected override void OnDragStartedHook()
|
|
||||||
{
|
|
||||||
// Your logic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Inherit from `DraggableVisual`:
|
|
||||||
```csharp
|
|
||||||
public class MyCustomVisual : DraggableVisual
|
|
||||||
{
|
|
||||||
protected override void UpdateVisualContent()
|
|
||||||
{
|
|
||||||
// Update your visuals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Custom Slot Filtering
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// On DraggableSlot component:
|
|
||||||
filterByType = true
|
|
||||||
allowedTypeNames = { "CardDraggable", "BoosterPackDraggable" }
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
**Cards don't snap to slots:**
|
|
||||||
- Ensure SlotContainer has slots registered
|
|
||||||
- Check that slots aren't locked
|
|
||||||
- Verify type filtering isn't blocking the card
|
|
||||||
|
|
||||||
**Visuals don't follow smoothly:**
|
|
||||||
- Check followSpeed value (try 20-40)
|
|
||||||
- Ensure TiltParent and ShakeParent are assigned
|
|
||||||
- Verify the visual prefab has correct hierarchy
|
|
||||||
|
|
||||||
**Touch not working:**
|
|
||||||
- Ensure EventSystem exists in scene
|
|
||||||
- Check Canvas Raycast Target is enabled
|
|
||||||
- Verify GraphicRaycaster is on Canvas
|
|
||||||
|
|
||||||
**Cards jitter or shake:**
|
|
||||||
- Reduce followSpeed
|
|
||||||
- Disable idle animation
|
|
||||||
- Check for conflicting tweens
|
|
||||||
|
|
||||||
## Integration with Card System
|
|
||||||
|
|
||||||
The drag-and-drop system integrates seamlessly with your existing `CardSystemManager`:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// Spawn a draggable card from CardData
|
|
||||||
CardData cardData = CardSystemManager.Instance.GetAllCollectedCards()[0];
|
|
||||||
GameObject cardObj = Instantiate(cardDraggablePrefab, slotContainer.transform);
|
|
||||||
CardDraggable card = cardObj.GetComponent<CardDraggable>();
|
|
||||||
card.SetCardData(cardData);
|
|
||||||
|
|
||||||
// Assign to first available slot
|
|
||||||
DraggableSlot slot = slotContainer.GetAvailableSlots().FirstOrDefault();
|
|
||||||
if (slot != null)
|
|
||||||
{
|
|
||||||
card.AssignToSlot(slot, false);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
Inspired by the excellent feel of Balatro's card system (mixandjam/balatro-feel on GitHub).
|
|
||||||
|
|
||||||
Adapted for AppleHills card collection game with full touch support and Unity UI integration.
|
|
||||||
|
|
||||||
2031
docs/test_log.txt
2031
docs/test_log.txt
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user