263 lines
8.7 KiB
Markdown
263 lines
8.7 KiB
Markdown
# Item Example — Keycard (Key Item)
|
|
|
|
**Item Type:** `KeyItem`
|
|
**Complexity:** Low
|
|
**Systems Used:** `DA_ItemData`, `BP_ItemPickup`, `BPC_InventorySystem`, `BPC_KeyItemSystem`, `I_Lockable`, `BP_DoorActor`
|
|
**What You Learn:** Key item Data Asset, auto-protection from drop/clear, used-once pattern, door unlocking via `I_Lockable`
|
|
|
|
---
|
|
|
|
## 1. Create the DA_ItemData
|
|
|
|
### 1.1 — Create the Data Asset
|
|
|
|
```
|
|
Content Browser → Game/Items/
|
|
Right-click → Miscellaneous → Data Asset
|
|
Class: DA_ItemData
|
|
Name: DA_Item_Keycard_Omega
|
|
```
|
|
|
|
### 1.2 — Fill Properties
|
|
|
|
| Property | Value | Notes |
|
|
|----------|-------|-------|
|
|
| `Item Tag` | `Framework.Item.KeyItem.KeycardOmega` | Unique — registered in `DA_GameTagRegistry` |
|
|
| `Display Name` | "Omega Keycard" | Player sees this |
|
|
| `Description` | "A high-security keycard labeled 'Omega Wing.'" | Shown in journal/inventory |
|
|
| `Icon` | `T_Keycard_Icon` | Card-shaped texture |
|
|
| `World Mesh` | `SM_Keycard` | Flat card mesh |
|
|
| `Weight` | `0.1` | Very light |
|
|
| `Stack Limit` | `1` | One per slot — cannot stack keycards |
|
|
| `Item Type` | `KeyItem` | Key items are auto-protected |
|
|
| `b Is Key Item` | ✓ (checked) | This property also appears — it's a boolean flag |
|
|
| `b Can Be Dropped` | ✗ (unchecked) | Key items should NOT be droppable (auto-forced by `bIsKeyItem`) |
|
|
|
|
### 1.3 — Save
|
|
|
|
No sub-data needed. Key items don't have Equipment or Consumable data.
|
|
|
|
---
|
|
|
|
## 2. Create the BP_Pickup_KeycardOmega
|
|
|
|
Same pattern as other pickups:
|
|
|
|
### 2.1 — Create Blueprint
|
|
|
|
```
|
|
Content Browser → Game/Pickups/
|
|
Right-click → Blueprint Class → Actor
|
|
Name: BP_Pickup_KeycardOmega
|
|
```
|
|
|
|
### 2.2 — Components
|
|
|
|
| # | Component | Name | Purpose |
|
|
|---|-----------|------|---------|
|
|
| 1 | `StaticMeshComponent` | `Mesh` | Card model |
|
|
| 2 | `SphereComponent` | `PickupTrigger` | Radius 150, `OverlapOnlyPawn` |
|
|
|
|
### 2.3 — Variable
|
|
|
|
`ItemData` → Type: `DA_ItemData → Object Reference` → Instance Editable ✓
|
|
|
|
### 2.4 — Construction Script (same pattern)
|
|
|
|
```
|
|
ItemData → Get World Mesh → Load Synchronous → Set Static Mesh (Mesh)
|
|
ItemData → Get Display Name → Set Actor Label
|
|
```
|
|
|
|
### 2.5 — I_Interactable Wiring (same pattern)
|
|
|
|
```
|
|
Interactor → Get BPC_InventorySystem → CanAddItem(ItemData, 1)
|
|
True → AddItem → Destroy Actor → Return True
|
|
False → Print "Inventory Full" → Return False
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Create the Lockable Door
|
|
|
|
### 3.1 — Create Door Blueprint
|
|
|
|
```
|
|
Content Browser → Game/Actors/
|
|
Right-click → Blueprint Class → Actor (or BP_DoorActor from framework)
|
|
Name: BP_Door_OmegaWing
|
|
```
|
|
|
|
### 3.2 — Add Components
|
|
|
|
| # | Component | Name | Purpose |
|
|
|---|-----------|------|---------|
|
|
| 1 | `StaticMeshComponent` | `DoorFrame` | The door frame (static) |
|
|
| 2 | `StaticMeshComponent` | `DoorPanel` | The moving door part |
|
|
| 3 | `BoxComponent` | `InteractionTrigger` | Door interaction range |
|
|
|
|
### 3.3 — Add Interfaces
|
|
|
|
Class Settings → Interfaces → Add:
|
|
- `UInteractable`
|
|
- `ULockable`
|
|
|
|
### 3.4 — Variables
|
|
|
|
| Variable | Type | Default | Purpose |
|
|
|----------|------|---------|---------|
|
|
| `bIsLocked` | Boolean | `true` | Door starts locked |
|
|
| `bIsOpen` | Boolean | `false` | Door starts closed |
|
|
| `RequiredKeyTag` | GameplayTag | `Framework.Item.KeyItem.KeycardOmega` | Which key unlocks this |
|
|
|
|
### 3.5 — Wire I_Lockable
|
|
|
|
```
|
|
Event Try Unlock (Interface -> ULockable)
|
|
│ Unlocker: AActor*, KeyTag: FGameplayTag
|
|
│ Return Boolean
|
|
│
|
|
├─ bIsLocked? → Branch
|
|
│ ├─ True:
|
|
│ │ ├─ KeyTag == RequiredKeyTag? → Branch
|
|
│ │ │ ├─ True:
|
|
│ │ │ │ ├─ Set bIsLocked = false
|
|
│ │ │ │ ├─ Unlocker → Get BPC_KeyItemSystem
|
|
│ │ │ │ │ └─ Consume Key (KeyTag) ← removes key from inventory
|
|
│ │ │ │ ├─ Print "Door unlocked with Omega Keycard"
|
|
│ │ │ │ └─ Return True
|
|
│ │ │ │
|
|
│ │ │ └─ False:
|
|
│ │ │ ├─ Print "Wrong key — requires Omega Keycard"
|
|
│ │ │ └─ Return False
|
|
│ │ │
|
|
│ │ └─ False: (already unlocked)
|
|
│ │ └─ Return True
|
|
|
|
Event Is Locked
|
|
│ Return Boolean
|
|
└─ Return bIsLocked
|
|
|
|
Event Get Required Key Tag
|
|
│ Return FGameplayTag
|
|
└─ Return RequiredKeyTag
|
|
|
|
Event Try Lock
|
|
│ Locker: AActor*
|
|
│ Return Boolean
|
|
└─ Set bIsLocked = true → Return True (re-lockable for puzzle purposes)
|
|
```
|
|
|
|
### 3.6 — Wire I_Interactable (on door)
|
|
|
|
```
|
|
Event Interact (Interface -> UInteractable)
|
|
│ Interactor: AActor*
|
|
│ Return Boolean
|
|
│
|
|
├─ bIsLocked? → Branch
|
|
│ ├─ True:
|
|
│ │ ├─ Interactor → Get BPC_KeyItemSystem
|
|
│ │ │ └─ Has Key(RequiredKeyTag)?
|
|
│ │ │ ├─ True:
|
|
│ │ │ │ ├─ Call Try Unlock (self, Interactor, RequiredKeyTag)
|
|
│ │ │ │ └─ (If unlocked) → Open Door (see below)
|
|
│ │ │ │
|
|
│ │ │ └─ False:
|
|
│ │ │ ├─ Print "Door is locked. Find Omega Keycard."
|
|
│ │ │ └─ Return False
|
|
│ │ │
|
|
│ │ └─ Return False
|
|
│ │
|
|
│ └─ False: (door is unlocked)
|
|
│ ├─ bIsOpen? → Branch
|
|
│ │ ├─ True → Close Door → Return True
|
|
│ │ └─ False → Open Door → Return True
|
|
|
|
Function: Open Door
|
|
│
|
|
├─ Timeline (Rotation track, 0 → OpenAngle over OpenDuration)
|
|
│ └─ Update: DoorPanel → Set Relative Rotation
|
|
├─ Set bIsOpen = true
|
|
└─ (Optional) Play door creak sound
|
|
|
|
Function: Close Door
|
|
│
|
|
├─ Timeline (Rotation track, OpenAngle → 0 over CloseDuration)
|
|
│ └─ Update: DoorPanel → Set Relative Rotation
|
|
├─ Set bIsOpen = false
|
|
└─ (Optional) Play door close sound
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Wire BPC_KeyItemSystem (On Player Pawn)
|
|
|
|
The `BPC_KeyItemSystem` tracks which key items the player holds. It automates:
|
|
- Protecting key items from being dropped/cleared
|
|
- Validating key item requirements on door/lock interactions
|
|
- Removing consumed key items after use
|
|
|
|
In your BP child of `BPC_KeyItemSystem`:
|
|
|
|
```
|
|
Function: Has Key (KeyTag: GameplayTag) → Boolean
|
|
│
|
|
├─ Get Owner → Get BPC_InventorySystem
|
|
├─ Get All Items → For Each Loop
|
|
│ ├─ Item → Get bIsKeyItem → Branch
|
|
│ │ ├─ True: Item → Get ItemTag == KeyTag? → Return True
|
|
│ │ └─ False: Continue
|
|
│ │
|
|
│ └─ Loop end → Return False
|
|
|
|
Function: Consume Key (KeyTag: GameplayTag)
|
|
│
|
|
├─ Get Owner → Get BPC_InventorySystem
|
|
├─ Has Key(KeyTag)? → Branch
|
|
│ ├─ True: Inventory → Remove Item (by KeyTag, Quantity=1)
|
|
│ └─ False: Print "No such key in inventory"
|
|
```
|
|
|
|
> In the full framework, `BPC_KeyItemSystem` also prevents `Clear Inventory` and `Drop` operations from affecting key items by checking `bIsKeyItem` on the Data Asset.
|
|
|
|
---
|
|
|
|
## 5. Verification Checklist
|
|
|
|
**Step 1 — Pickup:**
|
|
- [ ] `BP_Pickup_KeycardOmega` placed in level, mesh visible
|
|
- [ ] Walk up → prompt "Pick up Omega Keycard" → press Interact → card goes to inventory
|
|
|
|
**Step 2 — Inventory Protection:**
|
|
- [ ] Keycard appears in inventory with "KEY" badge/indicator
|
|
- [ ] Try to drop keycard → blocked (cannot drop key items)
|
|
- [ ] Try "Clear Inventory" → keycard remains (protected)
|
|
|
|
**Step 3 — Door Interaction:**
|
|
- [ ] Walk up to `BP_Door_OmegaWing` while locked → prompt "Door is locked"
|
|
- [ ] Interact → door stays closed, shows "Requires Omega Keycard"
|
|
- [ ] Pick up keycard → walk to door → interact → door unlocks, keycard consumed from inventory
|
|
- [ ] Interact again → door opens
|
|
|
|
**Step 4 — Wrong Key:**
|
|
- [ ] Create a `DA_Item_Keycard_Beta` with a different tag
|
|
- [ ] Pick it up, try on Omega door → "Wrong key — requires Omega Keycard"
|
|
- [ ] Keycard_Beta stays in inventory (not consumed on wrong door)
|
|
|
|
---
|
|
|
|
## 6. KeyItem vs Regular Item — What's Different
|
|
|
|
| Behavior | Regular Item | Key Item (`bIsKeyItem = true`) |
|
|
|----------|-------------|-------------------------------|
|
|
| Can be dropped? | Yes (if `bCanBeDropped`) | No (auto-protected) |
|
|
| Can be cleared (death/new game)? | Yes | No (preserved across death) |
|
|
| Stacks | Yes (up to StackLimit) | Usually StackLimit=1 |
|
|
| Appears in inventory? | Yes | Yes, with KEY indicator |
|
|
| Consumed on use? | Depends on type | Yes (used once, then removed) |
|
|
| Sells to vendor? | Yes | No (protected from sale) |
|
|
|
|
Key items exist specifically to **gate progression**. They're a player's permanent proof of having solved a puzzle, explored an area, or defeated a boss. The framework ensures they can't be accidentally lost.
|