fix(ludic.physics): buoyant bodies in a table made with the state (256), a sink taking the last row - floating and sinking push nothing

ludic deps --allocs (25.2) found phys_float's five pushes per drop reaching the water and
phys_sink's filtered copies per removal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-28 15:56:12 +03:00
parent 58f0dbbc84
commit 7f973f9a4f
3 changed files with 24 additions and 30 deletions

View file

@ -35,8 +35,7 @@ export function phys_close(physics_st: mut PhysicsState) -> void {
} }
if physics_st.ph_shapes != null { List.clear(physics_st.ph_shapes) } if physics_st.ph_shapes != null { List.clear(physics_st.ph_shapes) }
List.clear(physics_st.ph_spare) List.clear(physics_st.ph_spare)
List.clear(physics_st.ph_floats) physics_st.ph_nf = 0
List.clear(physics_st.ph_float_k)
if physics_st.ph_facts != null { q_clear(physics_st.ph_facts) } if physics_st.ph_facts != null { q_clear(physics_st.ph_facts) }
} }

View file

@ -46,10 +46,9 @@ export state PhysicsState {
ph_steps: int = 0 ph_steps: int = 0
ph_gen: int = 0 # how many worlds have been opened: an id from an older one is stale ph_gen: int = 0 # how many worlds have been opened: an id from an older one is stale
ph_hard: float = 2.0 # metres a second: a contact under this is not a fact ph_hard: float = 2.0 # metres a second: a contact under this is not a fact
ph_floats: []int = new []int # buoyant bodies' ids ph_floats: words = words(256) # buoyant bodies' ids, the first ph_nf of them
ph_float_k: []float = new []float # and theirs: buoyancy, linear drag, angular drag, wet ph_float_k: floats = floats(256 * 4) # and theirs: buoyancy, linear drag, angular drag, wet
ph_floats2: []int = new []int # the spare pair phys_sink filters into ph_nf: int = 0
ph_float_k2: []float = new []float
ph_rx: float = 0.0 # where the last phys_resolve put a body ph_rx: float = 0.0 # where the last phys_resolve put a body
ph_rz: float = 0.0 ph_rz: float = 0.0
ph_walkers: []pointer = new []pointer # a walker id is its place here; null once removed ph_walkers: []pointer = new []pointer # a walker id is its place here; null once removed

View file

@ -2,46 +2,42 @@
# carried by its current, and slowed by its drags. Reaching the water is a PHYS_SPLASH fact. # carried by its current, and slowed by its drags. Reaching the water is a PHYS_SPLASH fact.
const PH_K: int = 4 const PH_K: int = 4
# buoyancy 1 floats level with the surface, more rides higher; drags in 1/s # buoyancy 1 floats level with the surface, more rides higher; drags in 1/s. At most 256 float at
# once (a table made with the state): past that a body is simply not buoyed
export function phys_float(physics_st: mut PhysicsState, id: int, buoyancy: float, linear_drag: float, angular_drag: float) -> void { export function phys_float(physics_st: mut PhysicsState, id: int, buoyancy: float, linear_drag: float, angular_drag: float) -> void {
ph_buffers() ph_buffers()
phys_sink(physics_st, id) phys_sink(physics_st, id)
push(physics_st.ph_floats, id) if physics_st.ph_nf >= len(physics_st.ph_floats) { return }
push(physics_st.ph_float_k, buoyancy) let i = physics_st.ph_nf
push(physics_st.ph_float_k, linear_drag) physics_st.ph_floats[i] = id
push(physics_st.ph_float_k, angular_drag) physics_st.ph_float_k[i * PH_K] = buoyancy
push(physics_st.ph_float_k, 0.0) physics_st.ph_float_k[i * PH_K + 1] = linear_drag
physics_st.ph_float_k[i * PH_K + 2] = angular_drag
physics_st.ph_float_k[i * PH_K + 3] = 0.0
physics_st.ph_nf += 1
} }
# no longer floats (it is still a body); every removal asks, so the lists are filtered into a kept # no longer floats (it is still a body): the last one takes its row
# spare pair and swapped, never made anew
export function phys_sink(physics_st: mut PhysicsState, id: int) -> void { export function phys_sink(physics_st: mut PhysicsState, id: int) -> void {
if physics_st.ph_floats == null { return } for i in 0 .. physics_st.ph_nf {
let ids = physics_st.ph_floats2 if physics_st.ph_floats[i] == id {
let ks = physics_st.ph_float_k2 let last = physics_st.ph_nf - 1
List.clear(ids) physics_st.ph_floats[i] = physics_st.ph_floats[last]
List.clear(ks) for k in 0 .. PH_K { physics_st.ph_float_k[i * PH_K + k] = physics_st.ph_float_k[last * PH_K + k] }
for i in 0 .. len(physics_st.ph_floats) { physics_st.ph_nf = last
if physics_st.ph_floats[i] != id { return
push(ids, physics_st.ph_floats[i])
for k in 0 .. PH_K { push(ks, physics_st.ph_float_k[i * PH_K + k]) }
} }
} }
physics_st.ph_floats2 = physics_st.ph_floats
physics_st.ph_float_k2 = physics_st.ph_float_k
physics_st.ph_floats = ids
physics_st.ph_float_k = ks
} }
export function phys_floating(physics_st: PhysicsState, id: int) -> bool { export function phys_floating(physics_st: PhysicsState, id: int) -> bool {
if physics_st.ph_floats == null { return false } for i in 0 .. physics_st.ph_nf { if physics_st.ph_floats[i] == id { return true } }
for i in 0 .. len(physics_st.ph_floats) { if physics_st.ph_floats[i] == id { return true } }
return false return false
} }
function ph_buoy_all(physics_st: mut PhysicsState) -> void { function ph_buoy_all(physics_st: mut PhysicsState) -> void {
let dt = physics_st.ph_step let dt = physics_st.ph_step
for i in 0 .. len(physics_st.ph_floats) { for i in 0 .. physics_st.ph_nf {
let id = physics_st.ph_floats[i] let id = physics_st.ph_floats[i]
if jph_body_read(physics_st.ph_world, id, physics_st.ph_vals) == 0 { if jph_body_read(physics_st.ph_world, id, physics_st.ph_vals) == 0 {
ph_buoy_one(physics_st, i, id, physics_st.ph_vals[0], physics_st.ph_vals[2], dt) ph_buoy_one(physics_st, i, id, physics_st.ph_vals[0], physics_st.ph_vals[2], dt)