mirror of
https://github.com/vladtrc/iw4L
synced 2026-10-26 02:11:39 -04:00
Let shot desk props move from where they are placed, and stand on desks
A placed prop often starts inside the world: a monitor's stand sits a
hair inside the desk, and its unrotated model bounds reach into the
cubicle wall behind it. integrate_body stops a body that starts inside,
so such a prop never moved however often it was shot, such as the
back-office com_widescreen_monitor on mp_terminal. The physics also
collided only with solid, while a static-model desk stands in the
clipmap as item clip, so a keyboard or phone knocked off its spot
dropped through the desk to the floor.
On its first wake a body now takes the nearest clear pose (small lifts
up to 2 units, then a footprint narrowed to 75% or 50%), colliding with
solid and item clip where it can and with solid alone where it can't,
and keeps that mask. A prop with no clear pose stays where it was
placed and settles, as 61b7c43 made it. Props still only slide; they
don't tip over.
Measured on our build with a replay of the map data: of the 1007
mp_terminal dynents with physics, 78 started stuck and this frees 38 of
them, and it freezes none that moved before. On an iPhone build on
mp_terminal, the back-office keyboards, phones and monitors moved when
shot and stayed on their desks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,10 @@ const MSEC_STEP: i32 = 17;
|
||||
const MAX_ITERS: i32 = 2;
|
||||
|
||||
const CONTENTS_SOLID: u32 = 1;
|
||||
const CONTENTS_ITEMCLIP: u32 = 0x400;
|
||||
const WAKE_MASKS: [u32; 2] = [CONTENTS_SOLID | CONTENTS_ITEMCLIP, CONTENTS_SOLID];
|
||||
const WAKE_LIFTS: [f32; 6] = [0.0, CONTACT_SLOP, 0.25, 0.5, 1.0, 2.0];
|
||||
const WAKE_FOOTPRINTS: [f32; 3] = [1.0, 0.75, 0.5];
|
||||
const SLEEP_SPEED: f32 = 4.0;
|
||||
const GROUND_NZ: f32 = 0.7;
|
||||
const CONTACT_SLOP: f32 = 0.125;
|
||||
@@ -56,6 +60,7 @@ struct DynEntPhysBody {
|
||||
maxs: [f32; 3],
|
||||
bounce: f32,
|
||||
friction: f32,
|
||||
mask: u32,
|
||||
on_ground: bool,
|
||||
asleep_ms: i32,
|
||||
}
|
||||
@@ -99,6 +104,7 @@ pub fn step_phys_world0(
|
||||
}
|
||||
let (mins, maxs) = xmodel_phys_hull(catalog, &inst.current_model);
|
||||
let add_vel = impulse.impulse / preset.mass;
|
||||
let phys_clip = clip.0.as_deref();
|
||||
world
|
||||
.bodies
|
||||
.entry(entity)
|
||||
@@ -106,15 +112,22 @@ pub fn step_phys_world0(
|
||||
body.vel += add_vel;
|
||||
body.asleep_ms = 0;
|
||||
})
|
||||
.or_insert_with(|| DynEntPhysBody {
|
||||
origin: transform.translation,
|
||||
vel: add_vel,
|
||||
mins,
|
||||
maxs,
|
||||
bounce: preset.bounce,
|
||||
friction: preset.friction,
|
||||
on_ground: false,
|
||||
asleep_ms: 0,
|
||||
.or_insert_with(|| {
|
||||
let pose = phys_clip
|
||||
.and_then(|clip| clear_wake_pose(clip, transform.translation, mins, maxs));
|
||||
let (origin, mins, maxs, mask) =
|
||||
pose.unwrap_or((transform.translation, mins, maxs, CONTENTS_SOLID));
|
||||
DynEntPhysBody {
|
||||
origin,
|
||||
vel: add_vel,
|
||||
mins,
|
||||
maxs,
|
||||
bounce: preset.bounce,
|
||||
friction: preset.friction,
|
||||
mask,
|
||||
on_ground: false,
|
||||
asleep_ms: 0,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -185,6 +198,39 @@ pub fn step_phys_world0(
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_wake_pose(
|
||||
clip: &ClipCollision,
|
||||
origin: Vec3,
|
||||
mins: [f32; 3],
|
||||
maxs: [f32; 3],
|
||||
) -> Option<(Vec3, [f32; 3], [f32; 3], u32)> {
|
||||
for mask in WAKE_MASKS {
|
||||
for scale in WAKE_FOOTPRINTS {
|
||||
let (mins, maxs) = narrowed_footprint(mins, maxs, scale);
|
||||
for lift in WAKE_LIFTS {
|
||||
let at = (origin + Vec3::Z * lift).to_array();
|
||||
let probe = clip.sweep_box(at, at, mins, maxs, mask);
|
||||
if !probe.startsolid && !probe.allsolid {
|
||||
return Some((Vec3::from_array(at), mins, maxs, mask));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn narrowed_footprint(mins: [f32; 3], maxs: [f32; 3], scale: f32) -> ([f32; 3], [f32; 3]) {
|
||||
let mut lo = mins;
|
||||
let mut hi = maxs;
|
||||
for axis in 0..2 {
|
||||
let mid = (mins[axis] + maxs[axis]) * 0.5;
|
||||
let half = (maxs[axis] - mins[axis]) * 0.5 * scale;
|
||||
lo[axis] = mid - half;
|
||||
hi[axis] = mid + half;
|
||||
}
|
||||
(lo, hi)
|
||||
}
|
||||
|
||||
fn integrate_free(body: &mut DynEntPhysBody, dt: f32) {
|
||||
body.vel.z += GRAVITY_Z * dt;
|
||||
body.origin += body.vel * dt;
|
||||
@@ -200,7 +246,7 @@ fn integrate_body(body: &mut DynEntPhysBody, clip: &ClipCollision, dt: f32) {
|
||||
end.to_array(),
|
||||
body.mins,
|
||||
body.maxs,
|
||||
CONTENTS_SOLID,
|
||||
body.mask,
|
||||
);
|
||||
if hit.allsolid || hit.startsolid {
|
||||
body.vel = Vec3::ZERO;
|
||||
|
||||
Reference in New Issue
Block a user