use rapier2d::prelude::*;
struct OneWayPlatformHook {
platform: ColliderHandle,
}
impl PhysicsHooks for OneWayPlatformHook {
fn modify_solver_contacts(&self, context: &mut ContactModificationContext) {
let allowed_local_n1 = if context.collider1 == self.platform {
Vector::Y
} else {
-Vector::Y
};
context.update_as_oneway_platform(allowed_local_n1, 0.1);
}
}
#[test]
fn oneway_platform_with_custom_normal() {
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let mut impulse_joints = ImpulseJointSet::new();
let mut multibody_joints = MultibodyJointSet::new();
let mut pipeline = PhysicsPipeline::new();
let mut bf = BroadPhaseBvh::new();
let mut nf = NarrowPhase::new();
let mut islands = IslandManager::new();
let mut ccd = CCDSolver::new();
let params = IntegrationParameters::default();
let gravity = Vector::new(0.0, -9.81);
let ground = bodies.insert(RigidBodyBuilder::fixed());
let platform = colliders.insert_with_parent(
ColliderBuilder::cuboid(2.0, 0.1).active_hooks(ActiveHooks::MODIFY_SOLVER_CONTACTS),
ground,
&mut bodies,
);
let ball = bodies.insert(
RigidBodyBuilder::dynamic()
.translation(Vector::new(0.0, -3.0))
.linvel(Vector::new(0.0, 12.0)),
);
colliders.insert_with_parent(ColliderBuilder::ball(0.25), ball, &mut bodies);
let hooks = OneWayPlatformHook { platform };
let mut max_y: Real = -3.0;
for _ in 0..300 {
pipeline.step(
gravity,
¶ms,
&mut islands,
&mut bf,
&mut nf,
&mut bodies,
&mut colliders,
&mut impulse_joints,
&mut multibody_joints,
&mut ccd,
&hooks,
&(),
);
max_y = max_y.max(bodies[ball].translation().y);
}
assert!(
max_y > 1.0,
"ball did not pass through the platform from below (max_y = {max_y})"
);
let final_y = bodies[ball].translation().y;
assert!(
(0.2..0.6).contains(&final_y),
"ball did not land on top of the platform (final_y = {final_y})"
);
}