From 7f973f9a4f69a2ebc06ea45783426d10413b55fc Mon Sep 17 00:00:00 2001 From: Orkuncakilkaya Date: Mon, 28 Sep 2026 15:56:12 +0300 Subject: [PATCH] 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 --- packages/ludic.physics/shapes.ludic | 3 +- packages/ludic.physics/state.ludic | 7 ++--- packages/ludic.physics/water.ludic | 44 +++++++++++++---------------- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/packages/ludic.physics/shapes.ludic b/packages/ludic.physics/shapes.ludic index f72ae383..c09444df 100644 --- a/packages/ludic.physics/shapes.ludic +++ b/packages/ludic.physics/shapes.ludic @@ -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) } List.clear(physics_st.ph_spare) - List.clear(physics_st.ph_floats) - List.clear(physics_st.ph_float_k) + physics_st.ph_nf = 0 if physics_st.ph_facts != null { q_clear(physics_st.ph_facts) } } diff --git a/packages/ludic.physics/state.ludic b/packages/ludic.physics/state.ludic index 5cbdc201..1ef9edb2 100644 --- a/packages/ludic.physics/state.ludic +++ b/packages/ludic.physics/state.ludic @@ -46,10 +46,9 @@ export state PhysicsState { ph_steps: int = 0 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_floats: []int = new []int # buoyant bodies' ids - ph_float_k: []float = new []float # and theirs: buoyancy, linear drag, angular drag, wet - ph_floats2: []int = new []int # the spare pair phys_sink filters into - ph_float_k2: []float = new []float + ph_floats: words = words(256) # buoyant bodies' ids, the first ph_nf of them + ph_float_k: floats = floats(256 * 4) # and theirs: buoyancy, linear drag, angular drag, wet + ph_nf: int = 0 ph_rx: float = 0.0 # where the last phys_resolve put a body ph_rz: float = 0.0 ph_walkers: []pointer = new []pointer # a walker id is its place here; null once removed diff --git a/packages/ludic.physics/water.ludic b/packages/ludic.physics/water.ludic index 7d73c34c..651e6637 100644 --- a/packages/ludic.physics/water.ludic +++ b/packages/ludic.physics/water.ludic @@ -2,46 +2,42 @@ # carried by its current, and slowed by its drags. Reaching the water is a PHYS_SPLASH fact. 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 { ph_buffers() phys_sink(physics_st, id) - push(physics_st.ph_floats, id) - push(physics_st.ph_float_k, buoyancy) - push(physics_st.ph_float_k, linear_drag) - push(physics_st.ph_float_k, angular_drag) - push(physics_st.ph_float_k, 0.0) + if physics_st.ph_nf >= len(physics_st.ph_floats) { return } + let i = physics_st.ph_nf + physics_st.ph_floats[i] = id + physics_st.ph_float_k[i * PH_K] = buoyancy + 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 -# spare pair and swapped, never made anew +# no longer floats (it is still a body): the last one takes its row export function phys_sink(physics_st: mut PhysicsState, id: int) -> void { - if physics_st.ph_floats == null { return } - let ids = physics_st.ph_floats2 - let ks = physics_st.ph_float_k2 - List.clear(ids) - List.clear(ks) - for i in 0 .. len(physics_st.ph_floats) { - if physics_st.ph_floats[i] != id { - push(ids, physics_st.ph_floats[i]) - for k in 0 .. PH_K { push(ks, physics_st.ph_float_k[i * PH_K + k]) } + for i in 0 .. physics_st.ph_nf { + if physics_st.ph_floats[i] == id { + let last = physics_st.ph_nf - 1 + physics_st.ph_floats[i] = physics_st.ph_floats[last] + for k in 0 .. PH_K { physics_st.ph_float_k[i * PH_K + k] = physics_st.ph_float_k[last * PH_K + k] } + physics_st.ph_nf = last + return } } - 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 { - if physics_st.ph_floats == null { return false } - for i in 0 .. len(physics_st.ph_floats) { if physics_st.ph_floats[i] == id { return true } } + for i in 0 .. physics_st.ph_nf { if physics_st.ph_floats[i] == id { return true } } return false } function ph_buoy_all(physics_st: mut PhysicsState) -> void { 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] 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)