- ludic.wildlife: WildlifeWorld.push / pushed_x / pushed_z (defaults change nothing); a ground walker's step is slid clear of a still thing with a body from its species' size and scale, and a step that gets nowhere turns away as the water does. Birds are not pushed; no dice added. - ludic.npc: NpcWorld.push / pushed_x / pushed_z (a person 0.35 m round) in npc_walk, and NpcWorld.clear (default true), which npc_line_ok asks at 1 m so a detour does not cut a trunk. - ludic.aim: AimView.clear replaces AimView.ground and the ground march; the pick asks the line a body's width short of where the ray enters the thing (aim_clear_at(t, back)), so a solid thing does not hide itself. probe.ludic (the ground-agreement probe) and AimView.dry are gone. - ludic.photo: PhotoLens.clear replaces PhotoLens.ground, PhotoLens.trunk and the march. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
2.7 KiB
Markdown
61 lines
2.7 KiB
Markdown
# ludic.aim
|
|
|
|
What the crosshair is on, and which thing the use key means. The crosshair is the exact middle of
|
|
the screen and the projection is symmetric, so the ray through it is the camera's position along its
|
|
forward - no unprojection. Each candidate is an upright cylinder widened by a fixed angular
|
|
forgiveness, and the pick is the nearest one the ray enters that nothing hides: the line up to
|
|
where the ray enters it is asked of the game (`clear`), so a thing that is itself solid does not
|
|
hide itself. Uses
|
|
[`ludic.base`](../ludic.base/README.md) and nothing else.
|
|
|
|
```ludic
|
|
import "ludic.aim"
|
|
```
|
|
|
|
The package keeps no list of things: the game offers every candidate each frame (`aim_offer`), keeps
|
|
the object behind the id it gave, and draws the rim and the prompt.
|
|
|
|
## The rule it keeps
|
|
|
|
**The crosshair decides WHICH, the distance decides WHETHER** (`aim_use(kind)`):
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| under the crosshair and in reach | `AIM_USE_THIS` - that, whatever else is nearer |
|
|
| under the crosshair and too far, within `AIM_USE_MAX` (10 m) | `AIM_USE_NOTHING` - and the prompt says why |
|
|
| nothing of that kind aimed at, or aimed past 10 m | `AIM_USE_NEAREST` - proximity is right again |
|
|
|
|
Every reach is floored at `AIM_REACH_MIN` (3 m) by `aim_reach_of(reach)`: a per-kind reach chosen
|
|
against its model was never chosen against standing between two props and looking at one. Anything
|
|
that asks "am I close enough to this" asks `aim_reach_of`.
|
|
|
|
## The port
|
|
|
|
```ludic
|
|
export port AimView {
|
|
x, y, z, fx, fy, fz, fov, # the camera (the ray)
|
|
clear: fn(ax, ay, az, bx, by, bz) -> bool, # nothing between: the ground and every still thing
|
|
body_x, body_z # distances and reach are the body's, not the camera's
|
|
}
|
|
```
|
|
|
|
Every member has a default: a camera 1.5 m up at the origin looking down -z at nothing in the way.
|
|
|
|
## API
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| `aim_begin()`, `aim_offer(kind, id, x, y0, y1, z, r, reach, far) -> bool` | a frame's candidates: true when this one is now the pick (`reach` `AIM_NEVER` is never in reach) |
|
|
| `aim_kind()` (`AIM_NONE` for nothing), `aim_id()`, `aim_dist()`, `aim_in_reach()`, `aim_t()`, `aim_off_centre()` | the pick |
|
|
| `aim_use(kind)` -> `AIM_USE_THIS` / `_NOTHING` / `_NEAREST`, `aim_reach_of(reach)` | the use key |
|
|
| `aim_ray_cyl(cx, y0, y1, cz, r)`, `aim_slack_m(dist)`, `aim_clear_to(x, y, z)`, `aim_clear_at(t, back)`, `aim_range(x, z)`, `aim_miss(cx, cz, r)` | the geometry, for a game's own probes (`aim_clear_at`: the ray clear to `back` short of t along it) |
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
ludic test packages/ludic.aim
|
|
```
|
|
|
|
A camera over flat ground with a ridge: the ray against a cylinder, the forgiveness, near before
|
|
far, the ridge hiding a thing and a solid thing not hiding itself, the reach floor and the three
|
|
answers for the use key.
|