# 5. Worked Example: A Door Prompt Part of [[Context-Sensitive Prompts and Onboarding]]. Prev: [[4. Context-Sensitive Prompt Volumes]]. Next: [[6. Prompt and Onboarding Pitfalls]]. Use a door that already exists, or the `KeyDoor` from [[3. Lock-and-Key Data]]. The point is the *prompt*, not a new latch. ## 5.1 Scene 1. An Input Actions asset with Interact (and a Keyboard and Gamepad binding), already wired as in [[Input System]] / [[5. Worked Example Remappable Player]]. 2. A `PanelRenderer` with the prompt UXML from part 3, Panel Settings, and a screen-space HUD ([[2.UI Toolkit Project Setup]]). 3. `PromptView` + `PromptBindingWatcher` on that GameObject. Assign the Interact `InputActionReference`, optional `PlayerInput`, and a `ControlIconSet` if you have a South-button sprite. 4. A door with a use trigger and a `PromptVolume` (`verb`: "Open" when unlocked, or start as "Locked" / "Open" based on state). `PromptBroker` in the scene, referenced by the volume and the view. 5. The door itself still handles Interact. Do not open the door from `PromptView`. If you have `KeyDoor`, hook `Unlocked` to change the volume verb to "Open" and call `RefreshAvailability`. While locked and the player has no key, the prompt can read "Locked" plus the Interact glyph - the binding is still truthful; the verb tells the state. ## 5.2 A thin KeyDoor hook ```csharp using UnityEngine; public sealed class KeyDoorPromptHook : MonoBehaviour { [SerializeField] KeyDoor door; [SerializeField] PromptVolume volume; [SerializeField] InventoryHolder player; void OnEnable() { if (door != null) { door.Unlocked += OnUnlocked; door.Opened += OnOpened; } if (player != null && player.Inventory != null) player.Inventory.Changed += OnInventoryChanged; ApplyVerb(); } void OnDisable() { if (door != null) { door.Unlocked -= OnUnlocked; door.Opened -= OnOpened; } if (player != null && player.Inventory != null) player.Inventory.Changed -= OnInventoryChanged; } void OnUnlocked(KeyDoor _) => ApplyVerb(); void OnOpened(KeyDoor _) => ApplyVerb(); void OnInventoryChanged() => ApplyVerb(); void ApplyVerb() { if (door == null || volume == null) return; volume.SetVerb(player != null ? door.PromptFor(player) : (door.IsLocked ? "Locked" : "Open")); volume.RefreshAvailability(); } } ``` `Inventory.Changed` is the event from [[Inventory Systems]]; if your inventory type uses a different name, subscribe to that instead of polling in `Update`. ## 5.3 Playtest checklist 1. Walk up to the locked door on keyboard: the prompt shows the current Interact key (not a hard-coded "E") and a locked or open verb. 2. Plug in a gamepad, press a pad button so the scheme switches: the glyph or "A" / South label replaces the key without leaving the volume. 3. Rebind Interact in your rebind UI, return to the door: the prompt matches the new binding. `PromptBindingWatcher.RaiseRefreshed` must have run. 4. Unlock the door: verb changes, binding stays. 5. Walk away: the prompt hides. Interact does nothing to that door out of range. 6. Two volumes: only the higher priority shows. ## 5.4 Onboarding beat (after the verbs work) When Jump, Interact, and a door already feel right, *then* gray-box a short first room: see the door, walk to it, read the prompt, open it (or fetch a key you can see). That is training built last ([[1. Prompt Design and Leave Training for Last]], [[ProBuilder Gray-Boxing and Landmarks]]). Do not invent a second Interact action for the tutorial. ## Exercise Add a pickup volume with a lower priority than the door. Standing in both, the door wins. Pick up the key first in a slightly separated volume, then the door verb changes - the layout still shows the door first (Level 12). ## Sources - [[3. Lock-and-Key Data]] - [[5. Worked Example Remappable Player]]