292 lines
8.8 KiB
Markdown
292 lines
8.8 KiB
Markdown
|
|
# Card Drag/Drop Integration - Refactor Summary
|
||
|
|
|
||
|
|
## What Was Changed
|
||
|
|
|
||
|
|
### ✅ **Files Modified:**
|
||
|
|
|
||
|
|
1. **Card.cs** - Now inherits from `DraggableObject`
|
||
|
|
- Added drag event hooks (`OnDragStartedHook`, `OnDragEndedHook`)
|
||
|
|
- Added setup methods for different flows (booster, album placement, album slot)
|
||
|
|
- Changed `Awake()` to `Initialize()` to match DraggableObject pattern
|
||
|
|
|
||
|
|
2. **CardDraggingState.cs** - Simplified to visual-only
|
||
|
|
- Removed position update methods (handled by DraggableObject base)
|
||
|
|
- Kept scale animation for visual feedback
|
||
|
|
- Removed redundant methods (`UpdateDragPosition`, `OnDroppedInSlot`, etc.)
|
||
|
|
|
||
|
|
### ✅ **Files Moved to DEPRECATED:**
|
||
|
|
|
||
|
|
- `CardDraggable.cs` → `DEPRECATED/` (redundant wrapper)
|
||
|
|
- `CardDraggableVisual.cs` → `DEPRECATED/` (tied to old system)
|
||
|
|
- `FlippableCard.cs` → `DEPRECATED/` (old card implementation)
|
||
|
|
|
||
|
|
**Note:** AlbumCardPlacementDraggable.cs remains in DragDrop/ for now (used by album corner cards)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## How It Works Now
|
||
|
|
|
||
|
|
### **Card.cs Inheritance Chain:**
|
||
|
|
```
|
||
|
|
Card → DraggableObject → MonoBehaviour
|
||
|
|
```
|
||
|
|
|
||
|
|
Card now has all DraggableObject capabilities:
|
||
|
|
- ✅ Drag/drop detection (OnBeginDrag, OnDrag, OnEndDrag)
|
||
|
|
- ✅ Slot detection and snapping
|
||
|
|
- ✅ Pointer events (OnPointerEnter, OnPointerExit, etc.)
|
||
|
|
- ✅ Enable/disable dragging via `SetDraggingEnabled(bool)`
|
||
|
|
|
||
|
|
### **Drag Event Flow:**
|
||
|
|
|
||
|
|
```
|
||
|
|
1. Player starts dragging card
|
||
|
|
↓
|
||
|
|
2. DraggableObject.OnBeginDrag() fires
|
||
|
|
↓
|
||
|
|
3. Calls Card.OnDragStartedHook()
|
||
|
|
↓
|
||
|
|
4. Card transitions to DraggingState
|
||
|
|
↓
|
||
|
|
5. DraggingState.OnEnterState() scales card up (visual feedback)
|
||
|
|
↓
|
||
|
|
6. Player drags (DraggableObject handles position updates)
|
||
|
|
↓
|
||
|
|
7. Player releases drag
|
||
|
|
↓
|
||
|
|
8. DraggableObject.OnEndDrag() fires
|
||
|
|
↓
|
||
|
|
9. DraggableObject finds closest slot
|
||
|
|
↓
|
||
|
|
10. Calls Card.OnDragEndedHook()
|
||
|
|
↓
|
||
|
|
11. Card checks if dropped in AlbumCardSlot:
|
||
|
|
- YES → Transition to PlacedInSlotState
|
||
|
|
- NO → Transition to RevealedState
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Setup Methods
|
||
|
|
|
||
|
|
### **For Booster Opening Flow:**
|
||
|
|
```csharp
|
||
|
|
card.SetupForBoosterReveal(cardData, isNew: true);
|
||
|
|
// - Starts in IdleState
|
||
|
|
// - Dragging DISABLED (booster cards can't be dragged)
|
||
|
|
```
|
||
|
|
|
||
|
|
### **For Album Placement Flow:**
|
||
|
|
```csharp
|
||
|
|
card.SetupForAlbumPlacement(cardData);
|
||
|
|
// - Starts in RevealedState
|
||
|
|
// - Dragging ENABLED (can drag to album slots)
|
||
|
|
```
|
||
|
|
|
||
|
|
### **For Cards Already in Album:**
|
||
|
|
```csharp
|
||
|
|
card.SetupForAlbumSlot(cardData, albumSlot);
|
||
|
|
// - Starts in PlacedInSlotState
|
||
|
|
// - Dragging DISABLED (can't drag out of album)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Integration with Existing Drag/Drop System
|
||
|
|
|
||
|
|
### **Works with AlbumCardSlot:**
|
||
|
|
```csharp
|
||
|
|
// AlbumCardSlot.cs doesn't need changes!
|
||
|
|
// It expects DraggableObject, and Card now IS a DraggableObject
|
||
|
|
public class AlbumCardSlot : DraggableSlot
|
||
|
|
{
|
||
|
|
public bool CanAccept(DraggableObject draggable)
|
||
|
|
{
|
||
|
|
// Works with Card because Card inherits from DraggableObject
|
||
|
|
if (draggable is Card card)
|
||
|
|
{
|
||
|
|
return CanAcceptCard(card.CardData);
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### **No Visual Component Needed:**
|
||
|
|
- DraggableObject can optionally use a DraggableVisual child
|
||
|
|
- Card doesn't need one - the state machine handles all visuals
|
||
|
|
- Card itself IS the visual representation
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## State Machine Integration
|
||
|
|
|
||
|
|
### **States that interact with drag system:**
|
||
|
|
|
||
|
|
1. **RevealedState** - Card waits here, dragging enabled
|
||
|
|
- Player can click to flip (if corner card)
|
||
|
|
- Player can drag to album slot (if placement card)
|
||
|
|
|
||
|
|
2. **DraggingState** - Visual feedback during drag
|
||
|
|
- Scales card up (1.1x by default)
|
||
|
|
- DraggableObject handles actual drag movement
|
||
|
|
|
||
|
|
3. **PlacedInSlotState** - Card placed in album
|
||
|
|
- Dragging disabled
|
||
|
|
- Can be clicked to enlarge
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Benefits
|
||
|
|
|
||
|
|
### **Cleaner Architecture:**
|
||
|
|
- ✅ No wrapper scripts needed (Card, CardDraggable, CardDraggableVisual → Just Card)
|
||
|
|
- ✅ Drag capability at top level (Card manages it directly)
|
||
|
|
- ✅ States handle visuals only (DraggingState shows scale, not position)
|
||
|
|
- ✅ Separation of concerns (drag logic ≠ visual logic)
|
||
|
|
|
||
|
|
### **Reuses Generic Base:**
|
||
|
|
- ✅ DraggableObject does all heavy lifting (snapping, slot detection, events)
|
||
|
|
- ✅ No card-specific drag code duplication
|
||
|
|
- ✅ Works with existing SlotContainer, DraggableSlot system
|
||
|
|
|
||
|
|
### **Backward Compatible:**
|
||
|
|
- ✅ Old files moved to DEPRECATED/ (not deleted)
|
||
|
|
- ✅ AlbumCardPlacementDraggable still exists for old corner cards
|
||
|
|
- ✅ Can migrate gradually (new Card works alongside old FlippableCard)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Testing Checklist
|
||
|
|
|
||
|
|
### **Booster Opening Flow:**
|
||
|
|
- [ ] Cards spawn in center (not draggable)
|
||
|
|
- [ ] Click card → flips → enlarges
|
||
|
|
- [ ] Tap enlarged card → shrinks to revealed state
|
||
|
|
- [ ] Try dragging card → should be blocked (dragging disabled)
|
||
|
|
|
||
|
|
### **Album Placement Flow:**
|
||
|
|
- [ ] Cards spawn in corner (draggable)
|
||
|
|
- [ ] Click card → flips → shows which card it is
|
||
|
|
- [ ] Card enters RevealedState (draggable)
|
||
|
|
- [ ] Drag card → enters DraggingState (scales up)
|
||
|
|
- [ ] Drop in valid AlbumCardSlot → PlacedInSlotState
|
||
|
|
- [ ] Drop outside slot → returns to RevealedState
|
||
|
|
- [ ] Card in slot is NOT draggable
|
||
|
|
|
||
|
|
### **Album Slot Interaction:**
|
||
|
|
- [ ] Click card in slot → AlbumEnlargedState
|
||
|
|
- [ ] Tap enlarged card → shrinks back to PlacedInSlotState
|
||
|
|
- [ ] Card cannot be dragged out of slot
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Migration Path for Old Code
|
||
|
|
|
||
|
|
### **Current State:**
|
||
|
|
- ✅ New Card.cs works with drag/drop
|
||
|
|
- ✅ Old FlippableCard.cs in DEPRECATED/ (still compiles)
|
||
|
|
- ✅ Old AlbumCardPlacementDraggable.cs still in DragDrop/ (for corner cards)
|
||
|
|
|
||
|
|
### **Next Steps:**
|
||
|
|
1. Update BoosterOpeningPage to use new Card.SetupForBoosterReveal()
|
||
|
|
2. Update AlbumViewPage corner cards to use Card.SetupForAlbumPlacement()
|
||
|
|
3. Test both flows thoroughly
|
||
|
|
4. Once stable, delete DEPRECATED/ folder
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Example Usage
|
||
|
|
|
||
|
|
### **BoosterOpeningPage.cs (New):**
|
||
|
|
```csharp
|
||
|
|
// Spawn booster cards (NOT draggable)
|
||
|
|
Card card = Instantiate(cardPrefab);
|
||
|
|
card.SetupForBoosterReveal(cardData, isNew: isNewCard);
|
||
|
|
card.Context.IsClickable = true;
|
||
|
|
|
||
|
|
// Subscribe to events
|
||
|
|
card.Context.OnFlipComplete += OnCardFlipComplete;
|
||
|
|
card.Context.OnCardInteractionComplete += OnCardComplete;
|
||
|
|
```
|
||
|
|
|
||
|
|
### **AlbumViewPage.cs (New - Corner Cards):**
|
||
|
|
```csharp
|
||
|
|
// Spawn unrevealed corner card (DRAGGABLE)
|
||
|
|
Card card = Instantiate(cardPrefab);
|
||
|
|
card.SetupForAlbumPlacement(cardData);
|
||
|
|
|
||
|
|
// Card can now be dragged to matching album slot
|
||
|
|
// When dropped, automatically transitions to PlacedInSlotState
|
||
|
|
```
|
||
|
|
|
||
|
|
### **AlbumViewPage.cs (New - Already Placed):**
|
||
|
|
```csharp
|
||
|
|
// Card already in album slot (NOT draggable)
|
||
|
|
Card card = Instantiate(cardPrefab, albumSlot.transform);
|
||
|
|
card.SetupForAlbumSlot(cardData, albumSlot);
|
||
|
|
|
||
|
|
// Card can be clicked to enlarge, but not dragged out
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Technical Notes
|
||
|
|
|
||
|
|
### **Why Card inherits from DraggableObject:**
|
||
|
|
- **Single Responsibility:** Card manages its own drag capability
|
||
|
|
- **No Wrappers:** Simpler prefab structure (no CardDraggable wrapper)
|
||
|
|
- **Polymorphism:** AlbumCardSlot accepts DraggableObject, Card IS a DraggableObject
|
||
|
|
- **Event Integration:** DraggableObject events trigger state transitions
|
||
|
|
|
||
|
|
### **Why DraggingState is visual-only:**
|
||
|
|
- **DraggableObject handles movement:** OnDrag() updates transform.position automatically
|
||
|
|
- **State shows feedback:** Scaling up indicates "I'm being dragged"
|
||
|
|
- **Clean separation:** Drag logic (base class) vs visual feedback (state)
|
||
|
|
|
||
|
|
### **Why SetDraggingEnabled():**
|
||
|
|
- **Booster cards:** Should never be draggable (opens in place)
|
||
|
|
- **Corner cards:** Should be draggable (placement flow)
|
||
|
|
- **Album cards:** Should NOT be draggable once placed (locked in slot)
|
||
|
|
- **Runtime control:** Can enable/disable per card instance
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Files Structure After Refactor
|
||
|
|
|
||
|
|
```
|
||
|
|
CardSystem/
|
||
|
|
├─ Card.cs ← NOW inherits from DraggableObject
|
||
|
|
├─ CardContext.cs
|
||
|
|
├─ CardAnimator.cs
|
||
|
|
├─ ProgressBarController.cs
|
||
|
|
├─ StateMachine/
|
||
|
|
│ ├─ States/
|
||
|
|
│ │ ├─ CardDraggingState.cs ← Simplified (visual-only)
|
||
|
|
│ │ ├─ CardRevealedState.cs ← Drag starts from here
|
||
|
|
│ │ ├─ CardPlacedInSlotState.cs ← Drag ends here (if valid slot)
|
||
|
|
│ │ └─ [other states...]
|
||
|
|
├─ DragDrop/
|
||
|
|
│ ├─ AlbumCardSlot.cs ← Works with Card (DraggableObject)
|
||
|
|
│ └─ AlbumCardPlacementDraggable.cs ← OLD system, for corner cards
|
||
|
|
└─ DEPRECATED/ ✨ NEW
|
||
|
|
├─ CardDraggable.cs ← Moved
|
||
|
|
├─ CardDraggableVisual.cs ← Moved
|
||
|
|
└─ FlippableCard.cs ← Moved
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Summary
|
||
|
|
|
||
|
|
✅ **Card.cs now inherits from DraggableObject** - Owns drag capability
|
||
|
|
✅ **Drag events trigger state transitions** - OnDragStarted → DraggingState
|
||
|
|
✅ **DraggingState is visual-only** - Shows scale feedback
|
||
|
|
✅ **Setup methods control dragging** - Enable/disable per flow
|
||
|
|
✅ **Backward compatible** - Old files in DEPRECATED/
|
||
|
|
✅ **Works with existing slots** - AlbumCardSlot unchanged
|
||
|
|
✅ **Cleaner architecture** - No wrappers, states handle visuals
|
||
|
|
|
||
|
|
**Status: Drag/Drop integration complete! Ready for testing and migration.**
|
||
|
|
|