ludic/packages/ludic.physics/walker.ludic

99 lines
4.3 KiB
Text

# 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)
}