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.
62 lines
3.6 KiB
Markdown
62 lines
3.6 KiB
Markdown
# 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.1–0.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, 75–90° 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.
|