Interaction system
Registers world entities as interactive, finds the closest one in reach of the player, shows its prompt with the player's own key, handles slow holds and refuses with a reason when a thing is locked or too far.
Interaction system (interaction.system) #
What it is for #
Registers world entities as interactive, finds the closest one in reach of the player, shows its prompt with the player's own key, handles slow holds and refuses with a reason when a thing is locked or too far.
It needs character.control, input.actions, game.engine; installing it brings them in.
Turn it on #
Install the kit in a project, then change a setting (the values shown are its defaults):
gripforge_gamekit_install { project_id: "gkp_…", id: "interaction.system" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "interaction.system",
config: { "radius": 2.5, "action": "interact" } }
First example #
<!-- test: kits/interaction_system/tests/interaction_system.rs::the_thing_within_reach_becomes_the_candidate_with_a_prompt --> This is the body of the passing test the_thing_within_reach_becomes_the_candidate_with_a_prompt; the helper functions it calls are defined at the top of the same test file.
#[test]
fn the_thing_within_reach_becomes_the_candidate_with_a_prompt() {
let (mut s, _, door) = scene(json!({}), [1.0, 0.0, 0.0], "Open door");
step(&mut s, 1);
assert_eq!(current(&mut s), json!(door));
let p = prompt_var(&s);
assert!(p.as_str().unwrap().contains("Open door"), "{p}");
assert_eq!(call(&mut s, PROMPT, "text", json!([])).unwrap(), p);
assert_eq!(
call(&mut s, PROMPT, "label", json!([])).unwrap(),
json!("Open door")
);
assert_eq!(
call(&mut s, PROMPT, "action", json!([])).unwrap(),
json!("interact")
);
assert_eq!(
call(&mut s, PROMPT, "target", json!([])).unwrap(),
json!(door)
);
assert_eq!(
call(&mut s, USE, "labelOf", json!([door])).unwrap(),
json!("Open door")
);
let seen = topics(&s, "interaction.available");
assert_eq!(seen.len(), 1);
assert_eq!(seen[0]["entity"], json!(door));
assert_eq!(seen[0]["action"], "interact");
// Still the same candidate a tick later: announced once.
step(&mut s, 3);
assert_eq!(topics(&s, "interaction.available").len(), 1);
}
Settings and defaults #
Descriptions come from the kit manifest and stay in English.
| Setting | Type | Default | Range or values | Meaning |
|---|---|---|---|---|
radius | number | 2.5 | 0.5–10 | Reach in meters from the player. |
action | string | "interact" | Input action that triggers the use. | |
showPrompt | boolean | true | ||
holdSeconds | number | 0 | 0–10 | 1.5.0: seconds the action is held before a use, for every interactive without its own hold (0: a press uses at once). |
vehicleScheme | string | "vehicle" | 1.6.0: the input.scheme scheme of a player at the wheel (input.scheme pushes it on vehicle.entered): then only the interactives… | |
vehicleRadius | number | 6 | 1–30 | 1.6.0: reach in metres from the vehicle the player drives. |
pointerTarget | boolean | false | 1.5.0: without input.scheme, the interactive under the pointer (the aim.target variable) is the candidate when in reach; with or… | |
clickApproach | boolean | false | 1.7.0: with pointerTarget, a click on an interactive out of reach walks the player to it (an input.scheme move order) and uses it… | |
approachSeconds | number | 8 | 0.5–30 | 1.7.0: the longest walk of a clickApproach before it is given up. |
Services, events, variables #
- Service
interaction.use: register(entity, label, action?, kind?) / unregister; kindOf(entity), setLocked(entity, on), setHold(entity, seconds), setFromVehicle(entity, on); the nearest interactive in range receives interaction.requested. - Service
interaction.prompt: The current prompt label as GameState interaction.prompt (E · Open door, key from labelFor); action() / label() / kind() / locked() of the current target, progress() of a hold (0..1, null when nothing is held) for ui.prompts and interaction.feedback. - Events emitted:
interaction.completed(entity,label) — A completion condition became true during play.interaction.available(entity,targetId,label,action) — An interactive entered reach (the HUD shows the prompt); entity is the interactive.interaction.hidden(entity) — No interactive in reach any more; entity is the one that was offered.interaction.requested(entity,target,targetId,label,action) — The player (entity) pressed an action on the available interactive (target).interaction.refused(entity,target,label,action,reason) — The use was refused: a tap of the hook interaction.use cancelled it (reason: the tap's, default refused), the interactive is locked (locked) or out…interaction.hold.started(entity,target,action,seconds) — 1.5.0: the player started holding the action on an interactive that needs a hold (seconds: how long).interaction.hold.cancelled(entity,target,action,progress) — 1.5.0: the hold stopped before its end (released, or the target changed).interaction.approach(entity,target,label,action) — 1.7.0: clickApproach — the player (entity) clicked an interactive out of reach (target) and walks to it; used on arrival.interaction.approach.cancelled(entity,target,action,reason) — 1.7.0: the walk of a clickApproach stopped before arrival (reason: replaced by another click, gone, timeout, no_player).
- Events listened to:
input.action,engine.state.changed,engine.visibility - Variables:
interaction.prompt(string) — Interaction prompt
Hooks and modding #
- Hooks (a game or a mod can intercept them):
interaction.use(cancellable) — The player (entity) pressed action on the interactive in reach (target): a door the story keeps shut, a lever that needs a tool.
- Moddable settings:
radius,action,showPrompt,holdSeconds,vehicleScheme,vehicleRadius,pointerTarget,clickApproach,approachSeconds - Components:
interactable
Engines #
Declared targets: web, godot, unity, unreal, rust. gripforge kit api interaction.system lists the exact settings and services of your version.
Versions #
Kit version 1.8.0.