8.8 KiB
Card Drag/Drop Integration - Refactor Summary
What Was Changed
✅ Files Modified:
-
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()toInitialize()to match DraggableObject pattern
- Added drag event hooks (
-
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:
card.SetupForBoosterReveal(cardData, isNew: true);
// - Starts in IdleState
// - Dragging DISABLED (booster cards can't be dragged)
For Album Placement Flow:
card.SetupForAlbumPlacement(cardData);
// - Starts in RevealedState
// - Dragging ENABLED (can drag to album slots)
For Cards Already in Album:
card.SetupForAlbumSlot(cardData, albumSlot);
// - Starts in PlacedInSlotState
// - Dragging DISABLED (can't drag out of album)
Integration with Existing Drag/Drop System
Works with AlbumCardSlot:
// 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:
-
RevealedState - Card waits here, dragging enabled
- Player can click to flip (if corner card)
- Player can drag to album slot (if placement card)
-
DraggingState - Visual feedback during drag
- Scales card up (1.1x by default)
- DraggableObject handles actual drag movement
-
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:
- Update BoosterOpeningPage to use new Card.SetupForBoosterReveal()
- Update AlbumViewPage corner cards to use Card.SetupForAlbumPlacement()
- Test both flows thoroughly
- Once stable, delete DEPRECATED/ folder
Example Usage
BoosterOpeningPage.cs (New):
// 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):
// 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):
// 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.