use alice_physics::collider::Contact;
use alice_physics::contact_cache::{BodyPairKey, ContactCache, ContactManifold};
use alice_physics::math::{Fix128, Vec3Fix};
fn touch(cache: &mut ContactCache, pair: BodyPairKey) {
let contact = Contact {
depth: Fix128::from_ratio(1, 100),
normal: Vec3Fix::UNIT_Y,
point_a: Vec3Fix::ZERO,
point_b: Vec3Fix::ZERO,
};
cache
.get_or_create(pair, Fix128::from_ratio(1, 2), Fix128::ZERO)
.add_or_update(&contact, Vec3Fix::ZERO, Vec3Fix::ZERO);
}
fn main() {
let pair = BodyPairKey::new(0, 1);
let mut m = ContactManifold::new(pair, Fix128::from_ratio(1, 2), Fix128::ZERO);
assert!(m.is_empty(), "a new manifold has no points");
m.add_or_update(
&Contact {
depth: Fix128::from_ratio(1, 50),
normal: Vec3Fix::UNIT_Y,
point_a: Vec3Fix::ZERO,
point_b: Vec3Fix::ZERO,
},
Vec3Fix::ZERO,
Vec3Fix::ZERO,
);
assert!(!m.is_empty(), "one point after add_or_update");
assert_eq!(m.normal, Vec3Fix::UNIT_Y, "shared normal of one point");
m.clear();
assert!(m.is_empty(), "clear drops every point");
assert_eq!(m.normal, Vec3Fix::ZERO, "clear resets the shared normal");
let mut cache = ContactCache::new();
let max_stale = cache.max_stale_frames;
let kept = BodyPairKey::new(0, 1);
let dropped = BodyPairKey::new(2, 3);
cache.begin_frame();
touch(&mut cache, kept);
touch(&mut cache, dropped);
cache.end_frame();
assert_eq!(cache.manifold_count(), 2);
for k in 1..=max_stale + 2 {
cache.begin_frame();
touch(&mut cache, kept);
cache.end_frame();
let expect_dropped_alive = k <= max_stale;
let dropped_alive = cache.find(&dropped).is_some();
println!(
"[contact_cache] end of frame {k}: abandoned pair alive = {dropped_alive} \
(closed form k <= {max_stale}: {expect_dropped_alive})"
);
assert_eq!(dropped_alive, expect_dropped_alive, "frame {k}");
if let Some(d) = cache.find(&dropped) {
assert_eq!(d.stale_frames, k, "stale_frames counts untouched frames");
}
assert_eq!(
cache.find(&kept).map(|m| m.stale_frames),
Some(0),
"touched pair is fresh every frame"
);
assert_eq!(
cache.manifold_count(),
1 + usize::from(expect_dropped_alive)
);
}
cache.clear();
assert_eq!(cache.manifold_count(), 0);
assert!(cache.find(&kept).is_none(), "the index is cleared too");
touch(&mut cache, kept);
assert_eq!(cache.manifold_count(), 1, "a cleared cache starts over");
assert_eq!(cache.total_contact_points(), 1);
println!(
"[contact_cache] abandoned pair expired after {} untouched frames, as derived",
max_stale + 1
);
}