test(physics): exercise every recovered collider
Probe both contact sides of all 109 recovered wall segments and every passive/scored circle. Verify each primitive detects overlap, separates the ball, and rejects inward maximum-speed motion. Test Plan: - cargo fmt --check - cargo test - cargo clippy --all-targets --all-features -- -D warnings - git diff --cached --check
This commit is contained in:
@@ -215,6 +215,7 @@ pub const BUMPERS: [StaticCircle; 3] = [
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::geometry::{circle_collision, segment_collision};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn recovered_object_inventory_is_complete() {
|
fn recovered_object_inventory_is_complete() {
|
||||||
@@ -238,4 +239,65 @@ mod tests {
|
|||||||
assert_eq!(shooter_wall.segment.start, Vec2::new(328.0, 422.0));
|
assert_eq!(shooter_wall.segment.start, Vec2::new(328.0, 422.0));
|
||||||
assert_eq!(shooter_wall.segment.end, Vec2::new(328.0, 58.0));
|
assert_eq!(shooter_wall.segment.end, Vec2::new(328.0, 58.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn every_recovered_wall_has_a_working_contact_surface_on_both_sides() {
|
||||||
|
for wall in WALLS {
|
||||||
|
let line = wall.segment.end - wall.segment.start;
|
||||||
|
assert!(
|
||||||
|
line.length_squared() > 0.0,
|
||||||
|
"object {} is degenerate",
|
||||||
|
wall.id
|
||||||
|
);
|
||||||
|
let normal = Vec2::new(-line.y, line.x).normalize();
|
||||||
|
let midpoint = (wall.segment.start + wall.segment.end) * 0.5;
|
||||||
|
|
||||||
|
for side in [-1.0, 1.0] {
|
||||||
|
let outward = normal * side;
|
||||||
|
let mut position = midpoint + outward * 0.5;
|
||||||
|
let mut velocity = -outward * 430.0;
|
||||||
|
let hit = segment_collision(&mut position, &mut velocity, 1.0, wall.segment);
|
||||||
|
|
||||||
|
assert!(hit, "object {} missed its midpoint contact", wall.id);
|
||||||
|
assert!(
|
||||||
|
velocity.dot(outward) >= 0.0,
|
||||||
|
"object {} did not reject an inward trajectory",
|
||||||
|
wall.id
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
position.distance(midpoint) >= 0.99,
|
||||||
|
"object {} did not separate the ball from its surface",
|
||||||
|
wall.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn every_recovered_circle_separates_and_reflects_the_ball() {
|
||||||
|
for circle in PASSIVE_CIRCLES.iter().chain(BUMPERS.iter()) {
|
||||||
|
let mut position = circle.center + Vec2::new(circle.contact_radius - 0.5, 0.0);
|
||||||
|
let mut velocity = Vec2::new(-430.0, 0.0);
|
||||||
|
let hit = circle_collision(
|
||||||
|
&mut position,
|
||||||
|
&mut velocity,
|
||||||
|
0.0,
|
||||||
|
circle.center,
|
||||||
|
circle.contact_radius,
|
||||||
|
0.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(hit, "object {} missed an overlapping ball", circle.id);
|
||||||
|
assert!(
|
||||||
|
position.x >= circle.center.x + circle.contact_radius,
|
||||||
|
"object {} did not separate the ball",
|
||||||
|
circle.id
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
velocity.x > 0.0,
|
||||||
|
"object {} did not reflect inward velocity",
|
||||||
|
circle.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user