Files
AppleHillsProduction/docs/drag_drop_system_readme.md

310 lines
7.7 KiB
Markdown
Raw Normal View History

2025-11-06 11:11:15 +01:00
# 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.