makepad/skills/makepad-gameplay-systems/references/input-and-camera.md
Arena Agent fe21c07d84 skills: add Makepad game skills pack ported from threejs-game-skills
Nine agent skills for building Makepad/Rust games, ported from
majidmanzarpour/threejs-game-skills. Same director-routed workflow and
premium bar; runtime rewritten for this fork's game crates.

- makepad-game-director        entrypoint, routing, continuity, asset probe
- makepad-gameplay-systems     loop, movers vs rigid bodies, input, camera, netplay
- makepad-aaa-graphics-builder lighting, shaders, budget, visual scorecard
- makepad-game-ui-designer     HUD, menus, touch and XR UI
- makepad-debug-profiler       defect bisection and profiling
- makepad-qa-release           verification ladder, evidence, packaging
- makepad-3d-generator         CC0 model search, casts, procedural geometry
- makepad-image-generator      texgen textures, palettes, sky, icons
- makepad-audio-generator      sample bank, mixer, material impacts, 3D audio

Written against the real APIs in libs/game/*, libs/sim and apps/arcade:
the game.* verb table, GameRenderer adaptive quality, the packed 6-float
GameMeshVertex layout, script_mod! splash styling, makepad-test driving,
and the BUDGETS.md numbers. No paid generation API is required - the CC0
library plus seeded makepad-game-gen replaces them.

Includes install.sh (Codex/Claude), validate-skills.sh and a repo-aware
probe_assets.sh; both scripts verified against this checkout.
2026-09-05 21:18:58 +00:00

62 lines
3.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Input and camera
## One action enum
Branch on device at the mapping layer only. Gameplay code must never ask which device is connected.
```rust
enum Action { MoveX(f32), MoveY(f32), Jump, Fire, Interact, Pause }
```
Sources: `RawInput` and `ControlSource` in `makepad-game-blocks`; `GameInputState` / `GamepadState` from `makepad_platform::event::game_input`; `DriveInput` for vehicles, with `drive_input_for(world, player)` in `makepad-game-session` for the networked case.
## Per-device rules
**Keyboard** — normalise diagonals (`(1,1)` normalised, or diagonal movement is 41% faster; this ships more often than it should). Support held keys via state, not key-repeat events.
**Gamepad** — radial deadzone ~0.15 (not per-axis, which produces a square deadzone and cross-shaped drift), rescale the remainder to full range so the first degree past the deadzone is not a jump to 0.15. Triggers are analog; use the range.
**Touch** — no hover, no right-click, and the thumb covers what it presses. Virtual sticks are relative to first-touch, not to a fixed screen point. Minimum 44 px targets. Every action needs a touch path or a mobile claim is false.
**XR** — see `apps/arcade/src/xr_input.rs` and `xr/`. Controller pose is not a gamepad axis: motion comes from the rig, aim from the hand. Snap-turn by default (smooth turning causes sickness); never move the camera without player input; keep HUD off the near plane — world- or wrist-anchored, not face-locked.
## Buffering and forgiveness
Store timestamps, not booleans:
```rust
if action_pressed(Action::Jump) { jump_pressed_at = now; }
let buffered = now - jump_pressed_at < 0.12;
let coyote = now - left_ground_at < 0.10;
if buffered && (on_floor || coyote) { do_jump(); jump_pressed_at = -1.0; }
```
Clear the buffer on use, or one press yields two jumps.
## Camera
`CameraRig` in `makepad-game-render` owns camera state; `scene_state(..)` builds the `SceneState3D` and `set_pass_camera(cx, &pass, &scene)` applies it. Script route: `camera`, `cam_dist`, `cam_yaw`, `cam_pitch`, `cam_fov`, `cam_shake`, `cam_dragging`, `chase`, `face`.
| Rig | Use | Notes |
| --- | --- | --- |
| Chase | vehicles, third-person action | lag on position, lead on velocity |
| Orbit | sandbox, inspection | drag to orbit, wheel to zoom (the `arcade_view` pattern) |
| Fixed / isometric | strategy, puzzle | no lag; readability over drama |
| First person | shooter, XR | no smoothing on look, ever |
**Lag and lookahead.** Position lags the target by ~0.10.2 s; the look point leads by velocity × ~0.3 s. Lag alone feels sluggish, lookahead alone feels twitchy; together they feel intentional.
**FOV.** 60° desktop third-person, 7590° first-person. Widen with speed (a few degrees) for a sense of acceleration — this is nearly free and very effective. In XR, FOV belongs to the headset: never set it.
**Collision.** Sphere-cast from target to camera and pull in on a hit, then ease back out slowly. Snapping out is more noticeable than snapping in.
**Shake.** Trauma-based: add trauma on impact, decay it, and use `trauma²` for amplitude so small hits stay subtle. Cap total displacement, and never shake in XR.
## Screen-space aiming
Convert a pointer to a world ray through the scene camera, then `cast_ray` with `raycast_filter()`. Filter out the player's own capsule.
## Testing input
`makepad-test` drives the real thing: `press_key`, `press_key_with_modifiers`, `type_text`, `touch_down`, plus `wait_for_log_contains` to synchronise. Test the mapping layer's output (the action stream) in a unit test, and the end-to-end path in one driven test — not every action end-to-end, which is slow and proves the same thing repeatedly.