feat(character): 16.9 - char_knock, a knock-back the walker carries (never into a trunk); a landing keeps only the air's speed along the body's facing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3fae64f975
commit
5c50755652
5 changed files with 39 additions and 3 deletions
|
|
@ -71,6 +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_knock(vx, vz, up)` | knocked off its feet (a shove): the walker carries it and it lands where the world lets it |
|
||||
| `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 |
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ export state CharacterState {
|
|||
chr_air: bool = false
|
||||
chr_air_vx: float = 0.0
|
||||
chr_air_vz: float = 0.0
|
||||
chr_knock: float = 0.0 # a knock-back's speed up, handed to the walker on the next step
|
||||
chr_land: float = 0.0 # seconds of the landing's crouch left
|
||||
chr_steep: float = 0.0 # seconds of "that was too steep" left to say
|
||||
chr_can_run: bool = true
|
||||
|
|
|
|||
|
|
@ -240,6 +240,20 @@ program CharacterTest {
|
|||
expect(not body_airborne(character_st))
|
||||
}
|
||||
|
||||
test "a knock-back carries the body off its feet, and a post stops it" (character_st: mut CharacterState) {
|
||||
fresh(character_st, 0.0, -2.0, 0.0)
|
||||
char_knock(character_st, 0.0, 5.0, 3.0)
|
||||
char_update(character_st, 0.0, 0.0, false, false, 0.0, 0.0, 1.0 / 60.0)
|
||||
expect(body_airborne(character_st))
|
||||
for i in 0 .. 120 { char_update(character_st, 0.0, 0.0, false, false, 0.0, 0.0, 1.0 / 60.0) }
|
||||
expect(not body_airborne(character_st))
|
||||
expect(body_z(character_st) > 0.5)
|
||||
fresh(character_st, -3.5, 0.0, 0.0)
|
||||
char_knock(character_st, -8.0, 0.0, 2.0)
|
||||
for i in 0 .. 120 { char_update(character_st, 0.0, 0.0, false, false, 0.0, 0.0, 1.0 / 60.0) }
|
||||
expect(body_x(character_st) > -5.2)
|
||||
}
|
||||
|
||||
test "the safe spot clears a collider, keeps out of deep water, and allows a wade when asked" (character_st: mut CharacterState) {
|
||||
expect(char_safe_spot(character_st, -6.0, 0.0, 0.0, 0.0))
|
||||
let dx = body_safe_x(character_st) + 6.0
|
||||
|
|
|
|||
|
|
@ -123,3 +123,14 @@ export function char_step_off(character_st: mut CharacterState, x: float, z: flo
|
|||
character_st.chr_z = z
|
||||
character_st.chr_y = CharacterGround.height(x, z)
|
||||
}
|
||||
|
||||
# knocked off its feet at (vx, vz) across and `up` upward (a bear's shove): the walker carries it,
|
||||
# so it lands wherever the world lets it - never inside a trunk. Not while swimming or riding.
|
||||
export function char_knock(character_st: mut CharacterState, vx: float, vz: float, up: float) -> void {
|
||||
if character_st.chr_swim or CharacterBody.riding() { return }
|
||||
character_st.chr_sit = false
|
||||
character_st.chr_air = true
|
||||
character_st.chr_air_vx = vx
|
||||
character_st.chr_air_vz = vz
|
||||
character_st.chr_knock = up
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,12 @@ function chr_walk(character_st: mut CharacterState, fx: float, fz: float, dx: fl
|
|||
var vx = fx * character_st.chr_speed
|
||||
var vz = fz * character_st.chr_speed
|
||||
var up = 0.0
|
||||
if character_st.chr_air {
|
||||
if character_st.chr_knock > 0.0 {
|
||||
up = character_st.chr_knock
|
||||
character_st.chr_knock = 0.0
|
||||
vx = character_st.chr_air_vx
|
||||
vz = character_st.chr_air_vz
|
||||
} else if character_st.chr_air {
|
||||
character_st.chr_air_vx = character_st.chr_air_vx + dx * (4.0 * dt)
|
||||
character_st.chr_air_vz = character_st.chr_air_vz + dz * (4.0 * dt)
|
||||
vx = character_st.chr_air_vx
|
||||
|
|
@ -60,6 +65,10 @@ function chr_walked(character_st: mut CharacterState, g: int, jumped: bool, dt:
|
|||
|
||||
function chr_landed(character_st: mut CharacterState) -> void {
|
||||
character_st.chr_land = 0.22
|
||||
character_st.chr_speed = Math.sqrt(character_st.chr_air_vx * character_st.chr_air_vx + character_st.chr_air_vz * character_st.chr_air_vz)
|
||||
chr_say(character_st, CHAR_LANDED, character_st.chr_speed)
|
||||
let carried = Math.sqrt(character_st.chr_air_vx * character_st.chr_air_vx + character_st.chr_air_vz * character_st.chr_air_vz)
|
||||
# the walk goes on only as fast as the air was carrying it the way it faces (a knock from the
|
||||
# front does not walk it back into what knocked it)
|
||||
let along = -Math.sin(character_st.chr_yaw) * character_st.chr_air_vx - Math.cos(character_st.chr_yaw) * character_st.chr_air_vz
|
||||
character_st.chr_speed = Math.max(along, 0.0)
|
||||
chr_say(character_st, CHAR_LANDED, carried)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue