Files
AppleHillsProduction/docs/custom_layout_guide.md
2025-11-06 15:27:08 +01:00

400 lines
9.6 KiB
Markdown

# 🎨 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!** 🎨