feat(character): 16.8 - on land a physics walker moves the body (CharacterGround.walk); the package's own gravity, ballistic air and slope-probe refusal are gone
The package keeps the rules and hands them over each step: speed and heading, whether a jump leaves, CHAR_STEP and the boots' slope limit. The walker (Jolt CharacterVirtual) does gravity, landing, steps, slopes and following the ground down. Too steep is ground too steep facing the way the body wanted to go; stepping off an edge is not. ludic.physics: phys_walker_move (follow the body if something else moved it, then step), the slope limit, the jump always honoured. The character's tests run on a real Jolt walker over the same fake world: 15 pass, a knee-high boulder now a step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d2cd775309
commit
e909ec122c
11 changed files with 169 additions and 89 deletions
|
|
@ -1,7 +1,7 @@
|
|||
# ludic.character
|
||||
|
||||
One walking body under a player's stick, seen from over its shoulder: the gait's walk and run with
|
||||
their acceleration, a jump with gravity, the step-versus-slope rule, wading that shelves into a swim,
|
||||
their acceleration, a jump, the step-versus-slope rule, wading that shelves into a swim,
|
||||
diving on a breath, sitting, one answer to "where can this body be put down", holds, being carried,
|
||||
and the orbit camera with its first-person eyes. Uses [`ludic.base`](../ludic.base/README.md) and
|
||||
nothing else.
|
||||
|
|
@ -19,10 +19,13 @@ sounds and charges the energy.
|
|||
|
||||
- **A pure query of the world stays pure.** `CharacterGround.height` is the world's ground and never
|
||||
the body's; what the feet can stand on is `char_stand_at(x, z, from_y)`, and only the movement asks.
|
||||
- **A step up and a slope up are different refusals** (`char_slope_blocks`). Within `CHAR_STEP`
|
||||
(0.55 m) of the feet is a step, taken whatever its gradient; above it the boots
|
||||
(`slope_limit`, a rise per metre) decide over `CHAR_SLOPE_PROBE` (0.6 m), never over the frame's
|
||||
own step - so 30 Hz and 240 Hz refuse at the same place.
|
||||
- **On land the game's physics walker moves the body** (`CharacterGround.walk`, phase 16: a Jolt
|
||||
CharacterVirtual in Maroon Lake). The package keeps the rules and hands them over each step: the
|
||||
speed and heading, whether a jump leaves (at 5 m/s), `CHAR_STEP` (0.55 m) as the step taken
|
||||
whatever its gradient, and the boots' `slope_limit` (a rise per metre) as the steepest ground.
|
||||
The walker does gravity, landing, steps, slopes and following the ground down, so 30 Hz and
|
||||
240 Hz refuse at the same place. `CHAR_WALK_STEEP` - ground too steep facing the way it wanted
|
||||
to go - is the refusal and the `CHAR_TOO_STEEP` fact; stepping off an edge is not.
|
||||
- **Where a body is put down is one question with one answer** (`char_safe_spot`): clear of every
|
||||
collider, no deeper than asked, within `CHAR_DROP` of the height left, on ground it can walk off.
|
||||
- **A collider has a height**: `push` takes the body's span (y0, y1), and `top_at` reports a top it
|
||||
|
|
@ -43,6 +46,8 @@ export port CharacterGround {
|
|||
slope: fn(float, float) -> float # 0 flat .. 1 wall (for sitting)
|
||||
slope_limit: fn() -> float # the boots: rise a metre (1.05)
|
||||
current: fn(float, float, float, float) -> float # (x, z, fx, fz): a stroke's share lost
|
||||
walk: fn(x, y, z, vx, vz, jump, step, max_slope_deg, dt) -> int # the land mover (required)
|
||||
walked_x / walked_y / walked_z: fn() -> float # ... to here
|
||||
}
|
||||
export port CharacterBody {
|
||||
pace, sneaking, breath, riding, ride(ix, iz, run, dt), holding, hold_x, hold_z, eyes_ok
|
||||
|
|
@ -52,7 +57,7 @@ export port CharacterInput {
|
|||
}
|
||||
```
|
||||
|
||||
Only `height` is required; unbound, the rest is a dry plain with no colliders, a fresh body and a
|
||||
`height`, `walk` and `walked_*` are required (the tests bind a real `ludic.physics` walker); unbound, the rest is a dry plain with no colliders, a fresh body and a
|
||||
still stick.
|
||||
|
||||
## API
|
||||
|
|
@ -66,7 +71,7 @@ still stick.
|
|||
| `char_hold(reason)`, `char_release(reason)` (`CHAR_HOLD_SCREEN`, `CHAR_HOLD_STAGE`) | holds by reason: two holders cannot release each other |
|
||||
| `char_board(x, z, yaw)`, `char_ride_at(x, y, z, yaw, speed)`, `char_step_off(x, z)` | carried by something (`CharacterBody.riding`/`ride`) |
|
||||
| `char_safe_spot(x, z, from_y, max_depth) -> bool`, `body_safe_x()`, `body_safe_z()` | somewhere to put a body down |
|
||||
| `char_stand_at(x, z, from_y)`, `char_slope_blocks(nh, fx, fz)` | the step rule, for a game's own movers |
|
||||
| `char_stand_at(x, z, from_y)` | the ground with a collider's top when it is a step, for a put-down |
|
||||
| `char_camera(dt)`, `char_camera_third(dt)`, `char_look(yaw, pitch)`, `char_look_pitch`, `char_orbit(dist)`, `char_lock_orbit`, `char_set_fps`, `char_fps_toggle() -> CHAR_EYES_*` | the camera; read it back with `body_eye_x/y/z/yaw/pitch()` and `body_eyes_now()` |
|
||||
| `body_x()`, `body_y()`, `body_z()`, `body_yaw()`, `body_speed()`, `body_moving()`, `body_run()`, `body_phase()`, `body_time()`, `body_water()`, `body_airborne()`, `body_vy()`, `body_landing()`, `body_steep()`, `body_step()`, `body_sitting()`, `body_sit_mode()`, `body_sit_t()`, `body_swimming()`, `body_diving()`, `body_depth()`, `body_breath()`, `body_breath_max()`, `body_floating()`, `body_swim_phase()`, `body_can_run()`, `body_held()`, `body_fps()`, `body_cam_yaw()`, `body_cam_pitch()`, `body_cam_dist()` | the queries |
|
||||
| `char_wrap(a)`, `char_toward(cur, target, rate)`, `char_ease(t)` | the helpers a pose needs |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue