# walker.ludic - a body that walks: Jolt's CharacterVirtual, stepped by the game with the speed it # wants across. Gravity, landing, steps up to ph step_up, slopes to max_slope and following the # ground down are Jolt's; a walker shoves dynamic things and a ray finds it (its `body`). export const PHYS_ON_GROUND: int = 0 export const PHYS_TOO_STEEP: int = 1 export const PHYS_UNSUPPORTED: int = 2 export const PHYS_IN_AIR: int = 3 export property PhysWalk { x: float = 0.0 # the feet y: float = 0.0 z: float = 0.0 vx: float = 0.0 vy: float = 0.0 vz: float = 0.0 ground: int = 3 # PHYS_ON_GROUND .. PHYS_IN_AIR ny: float = 1.0 # the ground normal's y: 1 flat body: int = -1 # its inner body, what rays and overlaps see } function ph_walker(physics_st: PhysicsState, id: int) -> pointer { if physics_st.ph_walkers == null or id < 0 or id >= len(physics_st.ph_walkers) { return null } return physics_st.ph_walkers[id] } # r wide and h tall, feet at (x, y, z), mass in kg; -1 with no world @creates(PhysWalker) export function phys_walker_add(physics_st: mut PhysicsState, r: float, h: float, x: float, y: float, z: float, max_slope: float, mass: float) -> int { if physics_st.ph_world == null { return -1 } ph_buffers() let k = jph_char_new(physics_st.ph_world, r, h, x, y, z, max_slope, mass) # a removed walker's place is taken again, so a horse called and sent away grows nothing for i in 0 .. len(physics_st.ph_walkers) { if physics_st.ph_walkers[i] == null { physics_st.ph_walkers[i] = k return i } } @alloc_ok("a slot for the most walkers at once; a removed one's slot is reused") push(physics_st.ph_walkers, k) return len(physics_st.ph_walkers) - 1 } # how high a step it takes without a jump, how far it follows the ground down, and the steepest # slope in degrees that is still ground export function phys_walker_limits(physics_st: PhysicsState, id: int, step_up: float, stick: float, max_slope: float) -> void { let k = ph_walker(physics_st, id) if k != null { jph_char_limits(k, step_up, stick, max_slope) } } @releases(PhysWalker) export function phys_walker_remove(physics_st: mut PhysicsState, id: int) -> void { let k = ph_walker(physics_st, id) if k == null { return } jph_char_free(k) physics_st.ph_walkers[id] = null } # one step of dt at (vx, vz) metres a second across; jump > 0 leaves the ground at that speed up. # Returns the ground state after it. export function phys_walker_step(physics_st: mut PhysicsState, id: int, dt: float, vx: float, vz: float, jump: float) -> int { let k = ph_walker(physics_st, id) if k == null or physics_st.ph_world == null { return PHYS_IN_AIR } return jph_char_step(physics_st.ph_world, k, dt, vx, vz, jump) } # where a walker is, into the caller's record; false when there is no such walker export function phys_walker_pose(physics_st: mut PhysicsState, id: int, p: PhysWalk) -> bool { let k = ph_walker(physics_st, id) if k == null { return false } jph_char_read(k, physics_st.ph_vals) let v = physics_st.ph_vals p.x = v[0]; p.y = v[1]; p.z = v[2] p.vx = v[3]; p.vy = v[4]; p.vz = v[5] p.ground = int(v[6]) p.ny = v[7] p.body = int(v[8]) return true } # put it somewhere, standing still: a teleport, a swap, getting off a boat export function phys_walker_place(physics_st: mut PhysicsState, id: int, x: float, y: float, z: float) -> void { let k = ph_walker(physics_st, id) if k != null and physics_st.ph_world != null { jph_char_place(physics_st.ph_world, k, x, y, z) } } # a body the game keeps elsewhere, moved by its walker: put where the body is if something else # moved it (a teleport, a ride, a swim), then one step under the given limits; the ground after it export function phys_walker_move(physics_st: mut PhysicsState, id: int, x: float, y: float, z: float, vx: float, vz: float, jump: float, step: float, max_slope: float, dt: float) -> int { let k = ph_walker(physics_st, id) if k == null { return PHYS_IN_AIR } jph_char_read(k, physics_st.ph_vals) let dx = physics_st.ph_vals[0] - x let dy = physics_st.ph_vals[1] - y let dz = physics_st.ph_vals[2] - z if dx * dx + dy * dy + dz * dz > 0.0025 { phys_walker_place(physics_st, id, x, y, z) } phys_walker_limits(physics_st, id, step, 0.5, max_slope) return phys_walker_step(physics_st, id, dt, vx, vz, jump) }