# 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.