fix(physics): process sensors before collision response
Evaluate type-three captures from the pre-movement position, retain their missing radial rim candidates, and run type-four motion randomization before candidate resolution and position publication. Sensor groups now execute in binary ID order without Hold or Complete prematurely aborting later records. Test Plan: - cargo test --all-targets - cargo clippy --all-targets --all-features -- -D warnings - rumdl check CHANGELOG.md RECONSTRUCTION.md README.md - git diff --check
This commit is contained in:
@@ -452,6 +452,48 @@ pub fn circle_collision_candidate(
|
||||
})
|
||||
}
|
||||
|
||||
/// Detect the non-capture boundary response of a type-3 record.
|
||||
pub fn capture_collision_candidate(
|
||||
old_position: MilliVec,
|
||||
velocity: MilliVec,
|
||||
center: Vec2,
|
||||
radius: f32,
|
||||
material: CollisionMaterial,
|
||||
) -> Option<StaticCollisionCandidate> {
|
||||
let center = MilliVec::from_position(center);
|
||||
let radius_milli = (radius * 1_000.0).round() as i32;
|
||||
let delta = MilliVec {
|
||||
x: center.x.wrapping_sub(old_position.x),
|
||||
y: center
|
||||
.y
|
||||
.wrapping_sub(old_position.y)
|
||||
.wrapping_sub(2_000),
|
||||
};
|
||||
let surface_distance = milli_distance(delta).wrapping_sub(radius_milli);
|
||||
let normal_x = Real48::from_i32(center.y.wrapping_sub(old_position.y));
|
||||
let normal_y = Real48::from_i32(old_position.x.wrapping_sub(center.x));
|
||||
let length = milli_distance(MilliVec {
|
||||
x: normal_x.round_i32(),
|
||||
y: normal_y.round_i32(),
|
||||
});
|
||||
if length == 0 {
|
||||
return None;
|
||||
}
|
||||
let normal_velocity = normal_velocity(velocity, normal_x, normal_y, length);
|
||||
if normal_velocity >= 0
|
||||
|| normal_velocity.wrapping_abs() < surface_distance.wrapping_abs()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
Some(StaticCollisionCandidate {
|
||||
surface_distance,
|
||||
normal_x,
|
||||
normal_y,
|
||||
normal_velocity,
|
||||
material,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn circle_collision_response(
|
||||
old_position: MilliVec,
|
||||
@@ -622,6 +664,27 @@ mod tests {
|
||||
assert_eq!(response.surface_distance, 2_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_three_boundary_builds_the_recovered_radial_candidate() {
|
||||
let candidate = capture_collision_candidate(
|
||||
MilliVec {
|
||||
x: 100_000,
|
||||
y: 100_000,
|
||||
},
|
||||
MilliVec { x: 1_000, y: 0 },
|
||||
vec2(103.0, 102.0),
|
||||
3.8,
|
||||
CollisionMaterial::line(0.6, 0.0),
|
||||
)
|
||||
.expect("the contacted type-three rim must retain a candidate");
|
||||
|
||||
assert_eq!(candidate.surface_distance, -800);
|
||||
assert_ne!(
|
||||
candidate.resolve(MilliVec { x: 1_000, y: 0 }, Real48::ZERO).velocity,
|
||||
MilliVec { x: 1_000, y: 0 }
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auxiliary_kick_uses_the_recovered_negative_speed_threshold() {
|
||||
let material = CollisionMaterial::line_with_kick(0.5, 0.1, -0.4, 0.4);
|
||||
|
||||
Reference in New Issue
Block a user