Code up the card part
This commit is contained in:
309
docs/drag_drop_system_readme.md
Normal file
309
docs/drag_drop_system_readme.md
Normal file
@@ -0,0 +1,309 @@
|
||||
# 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.
|
||||
|
||||
Reference in New Issue
Block a user