docs: Update item pickup setup instructions and add game examples for Blueprint walkthroughs

This commit is contained in:
Lefteris Notas
2026-05-21 20:45:44 +03:00
parent 7e876e4f0c
commit 44aca98885
4 changed files with 813 additions and 24 deletions

View File

@@ -46,23 +46,180 @@ Based on `Item Type`, fill the relevant sub-struct (other sub-panels auto-hide v
| `Ammo` | `AmmoData` (legacy) | AmmoTypeTag, PerPickupCount |
| `KeyItem`, `Document`, `Collectible`, `Resource`, `Misc` | None — core properties only | |
### Step 4 — Place a Pickup in the World
### Step 4 — Build the BP_ItemPickup Blueprint (one-time)
The Data Asset does **not** appear in the world. To spawn it:
The Data Asset does **not** appear in the world. You need a Blueprint Actor that references it. Here is the exact setup:
1. Create a `BP_ItemPickup` actor (see spec #25: [`../../04-inventory/25_BP_ItemPickup.md`](../04-inventory/25_BP_ItemPickup.md))
2. In the `BP_ItemPickup` actor instance, set `Config → Item Data` → your `DA_Item_MedKit`
3. Drag `BP_ItemPickup` into the level
4. The pickup reads the mesh from the Data Asset, handles overlap, and calls `BPC_InventorySystem.AddItem(ItemData)` on interact
#### 4.1 — Create the Blueprint
```
DA_Item_MedKit (Content Browser) ← defines WHAT the item is
Content Browser → Framework/Inventory/
Right-click → Blueprint Class → Actor
Name: BP_ItemPickup
```
#### 4.2 — Add Components
Open `BP_ItemPickup`**Viewport** tab → **Add Component** (top-left button):
| # | Component Class | Name | Purpose |
|---|----------------|------|---------|
| 1 | `StaticMeshComponent` | `Mesh` | Renders the item's 3D model in the world |
| 2 | `SphereComponent` | `InteractionCollision` | Detects when the player is near enough to pick up |
| 3 | *(optional)* `AudioComponent` | `PickupSound` | Plays a sound when collected |
**Select `InteractionCollision` → Details panel:**
- `Sphere Radius``150.0` (how close the player must be)
- Under **Collision Presets** → set to `OverlapOnlyPawn` (only the player triggers it)
#### 4.3 — Create the Config Variable
1. In the **My Blueprint** panel (left side), click **+ Variable**
2. Name: `Config`
3. Variable Type: **Struct → `S_PickupConfig`** (you may need to create this struct first — see spec #25 for its fields)
If `S_PickupConfig` doesn't exist yet, create it manually:
```
Content Browser → Framework/Inventory/
Right-click → Blueprints → Structure
Name: S_PickupConfig
Add fields:
ItemData → Type: DA_ItemData (Object Reference)
Quantity → Type: Integer, default: 1
bAutoRotate → Type: Boolean, default: true
bBobUpDown → Type: Boolean, default: true
BobAmplitude → Type: Float, default: 10.0
BobFrequency → Type: Float, default: 1.0
```
4. After creating the variable, select it → Details panel:
- **Instance Editable** → ✓ checked (so you can set it per-instance in the level)
- **Category** → `Pickup Config`
- **Tooltip** → "The item data asset this pickup represents"
#### 4.4 — Wire the Construction Script
Go to the **Construction Script** tab (or open the Construction Script graph). This runs every time you change the Config in the editor, so the mesh updates immediately.
```
Construction Script
├─ Get Config → Break S_PickupConfig → ItemData
│ │
│ ├─ Is Valid (ItemData)?
│ │ ├─ True → continue
│ │ └─ False → Print String "No ItemData assigned" (Editor-only) → Return
│ │
│ └─ ItemData → Get World Mesh (this is a soft reference — may not be loaded)
│ │
│ ├─ Is Valid (WorldMesh)?
│ │ ├─ True:
│ │ │ → Set Static Mesh (Mesh component, New Mesh = WorldMesh)
│ │ │ → ItemData → Get Display Name → Set Actor Label
│ │ └─ False:
│ │ → ItemData → World Mesh → Async Load Asset
│ │ → On Load Complete → Set Static Mesh
│ │
│ └─ ItemData → Get Icon → (cache for UI prompt)
```
**Key node-by-node:**
1. Drag the `Config` variable from My Blueprint → **Get Config**
2. **Break S_PickupConfig** (right-click the pin → Split Struct Pin, or drag off → "Break")
3. From the `ItemData` pin, drag off → Create a `IsValid` node
4. From the valid `ItemData` output, drag off → type `Get World Mesh` (this appears because `WorldMesh` is a `UPROPERTY` on `DA_ItemData`; if using soft reference, you'll get a `TSoftObjectPtr<UStaticMesh>` — connect to **Async Load Asset** or **Load Synchronous** for Construction Script)
5. From the resolved mesh, connect to `Set Static Mesh` node → target is the `Mesh` component (drag Mesh from the Components panel into the graph → Get)
#### 4.5 — Wire Interaction (I_Interactable)
**Step A — Add the Interface:**
1. **Class Settings** (toolbar button) → **Interfaces****Add** → select `UInteractable` (the C++ interface from `I_InterfaceLibrary.h`)
2. Compile. Now `Interact`, `Can Interact`, `Get Interaction Prompt` events appear in the right-click menu.
**Step B — Wire the Events:**
```
Event Interact (from I_Interactable)
│ Interactor: AActor*
├─ Get Config → Break → ItemData
├─ Interactor → Get Component by Class (BPC_InventorySystem)
│ │
│ └─ Is Valid?
│ ├─ False → Return (no inventory system on interactor)
│ └─ True → InventorySystem
│ │
│ ├─ Call Can Add Item(ItemData, Quantity from Config)
│ │ │
│ │ ├─ False → Print "Inventory Full" → Return
│ │ └─ True:
│ │ ├─ Call Add Item(ItemData, Quantity)
│ │ ├─ Play Sound at Location (PickupSound, GetActorLocation)
│ │ ├─ Destroy Actor
│ │ └─ Return
│ │
│ └─ (If ItemData has bIsInfinite or respawn logic — skip Destroy)
Event Can Interact (from I_Interactable)
│ Interactor, OutBlockReason (by ref)
├─ Is Config.ItemData Valid?
│ ├─ False → OutBlockReason = "No item data" → Return False
│ └─ True → Return True
Event Get Interaction Prompt (from I_Interactable)
├─ Get Config → ItemData → Get Display Name
└─ Return "Pick up [ItemName]"
```
#### 4.6 — Add Bobbing Rotation (optional polish)
In **Event Graph → Event BeginPlay**:
```
Event BeginPlay
├─ Get Config → Break → bAutoRotate
│ └─ True → Add Timeline → name: "BobAndRotate"
│ ├─ Update track:
│ │ ├─ Mesh → Add World Rotation (DeltaRotation = 0,0,Timeline.Rotation * 90)
│ │ └─ Mesh → Add World Offset (Delta = 0,0,Timeline.Bob * BobAmplitude * sin(time), ...)
│ │
│ └─ Timeline: float track 0→1 looping over 2 seconds
├─ Enable collision on InteractionCollision
└─ Bind OnComponentBeginOverlap(InteractionCollision) → Highlight mesh, show prompt
```
#### 4.7 — Compile and Use
1. **Compile → Save**
2. **Drag `BP_ItemPickup` into your level**
3. Select the instance → Details panel → **Pickup Config → Item Data** → select `DA_Item_MedKit`
4. Set `Quantity``1` (or more for stacked items)
5. The **Construction Script** runs immediately — the mesh should appear in the viewport
6. Position the actor where you want it
**Verification in PIE (Play In Editor):**
- The pickup should show its mesh, slowly rotating
- Walk up to it — the overlap event fires
- Press Interact — item goes into inventory, pickup disappears
- Open inventory → item should be in a slot with the correct name and icon
```
DA_Item_MedKit (Content Browser) ← defines IDENTITY
↑ referenced by
BP_ItemPickup (Actor in level) ← physical body in the world
BP_ItemPickup (Actor in level) ← physical BODY in world
├── StaticMeshComponent "Mesh" ← renders WorldMesh from Data Asset
├── SphereComponent "Collision" ← detects player proximity
└── Config struct ← holds pointer to DA_ItemData + quantity
↑ interacts via
BPC_InteractionDetector → BPC_InventorySystem.AddItem()
BPC_InteractionDetector → I_Interactable → BPC_InventorySystem.AddItem()
```
> **For concrete, step-by-step examples** of building specific item types (flashlight, pistol, medkit, keycard) with complete Blueprint graphs, component lists, and wiring diagrams, see the [`docs/game/`](../../game/README.md) directory.
---
## Single Identity Tag — Why One Tag Is Enough