diff options
Diffstat (limited to 'examples3d')
| -rw-r--r-- | examples3d/all_examples3.rs | 2 | ||||
| -rw-r--r-- | examples3d/damping3.rs | 2 | ||||
| -rw-r--r-- | examples3d/fountain3.rs | 6 | ||||
| -rw-r--r-- | examples3d/one_way_platforms3.rs | 143 |
4 files changed, 148 insertions, 5 deletions
diff --git a/examples3d/all_examples3.rs b/examples3d/all_examples3.rs index 9cbf4c3..8a71665 100644 --- a/examples3d/all_examples3.rs +++ b/examples3d/all_examples3.rs @@ -29,6 +29,7 @@ mod heightfield3; mod joints3; mod keva3; mod locked_rotations3; +mod one_way_platforms3; mod platform3; mod primitives3; mod restitution3; @@ -83,6 +84,7 @@ pub fn main() { ("Heightfield", heightfield3::init_world), ("Joints", joints3::init_world), ("Locked rotations", locked_rotations3::init_world), + ("One-way platforms", one_way_platforms3::init_world), ("Platform", platform3::init_world), ("Restitution", restitution3::init_world), ("Sensor", sensor3::init_world), diff --git a/examples3d/damping3.rs b/examples3d/damping3.rs index 8c68d3b..3847ceb 100644 --- a/examples3d/damping3.rs +++ b/examples3d/damping3.rs @@ -40,6 +40,6 @@ pub fn init_world(testbed: &mut Testbed) { /* * Set up the testbed. */ - testbed.set_world_with_gravity(bodies, colliders, joints, Vector3::zeros()); + testbed.set_world_with_params(bodies, colliders, joints, Vector3::zeros(), ()); testbed.look_at(Point3::new(2.0, 2.5, 20.0), Point3::new(2.0, 2.5, 0.0)); } diff --git a/examples3d/fountain3.rs b/examples3d/fountain3.rs index 5acc2e8..caaa21b 100644 --- a/examples3d/fountain3.rs +++ b/examples3d/fountain3.rs @@ -23,16 +23,14 @@ pub fn init_world(testbed: &mut Testbed) { let handle = bodies.insert(rigid_body); let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size).build(); colliders.insert(collider, handle, &mut bodies); - let mut k = 0; // Callback that will be executed on the main loop to handle proximities. - testbed.add_callback(move |mut window, mut graphics, physics, _, _| { - k += 1; + testbed.add_callback(move |mut window, mut graphics, physics, _, run_state| { let rigid_body = RigidBodyBuilder::new_dynamic() .translation(0.0, 10.0, 0.0) .build(); let handle = physics.bodies.insert(rigid_body); - let collider = match k % 3 { + let collider = match run_state.timestep_id % 3 { 0 => ColliderBuilder::round_cylinder(rad, rad, rad / 10.0).build(), 1 => ColliderBuilder::cone(rad, rad).build(), _ => ColliderBuilder::cuboid(rad, rad, rad).build(), diff --git a/examples3d/one_way_platforms3.rs b/examples3d/one_way_platforms3.rs new file mode 100644 index 0000000..173d03d --- /dev/null +++ b/examples3d/one_way_platforms3.rs @@ -0,0 +1,143 @@ +use na::{Point3, Vector3}; +use rapier3d::dynamics::{JointSet, RigidBodyBuilder, RigidBodySet}; +use rapier3d::geometry::{ColliderBuilder, ColliderHandle, ColliderSet}; +use rapier3d::pipeline::{ContactModificationContext, PhysicsHooks, PhysicsHooksFlags}; +use rapier_testbed3d::Testbed; + +struct OneWayPlatformHook { + platform1: ColliderHandle, + platform2: ColliderHandle, +} + +impl PhysicsHooks for OneWayPlatformHook { + fn active_hooks(&self) -> PhysicsHooksFlags { + PhysicsHooksFlags::MODIFY_SOLVER_CONTACTS + } + + fn modify_solver_contacts(&self, context: &mut ContactModificationContext) { + // The allowed normal for the first platform is its local +y axis, and the + // allowed normal for the second platform is its local -y axis. + // + // Now we have to be careful because the `manifold.local_n1` normal points + // toward the outside of the shape of `context.co1`. So we need to flip the + // allowed normal direction if the platform is in `context.collider_handle2`. + // + // Therefore: + // - If context.collider_handle1 == self.platform1 then the allowed normal is +y. + // - If context.collider_handle2 == self.platform1 then the allowed normal is -y. + // - If context.collider_handle1 == self.platform2 then its allowed normal +y needs to be flipped to -y. + // - If context.collider_handle2 == self.platform2 then the allowed normal -y needs to be flipped to +y. + let mut allowed_local_n1 = Vector3::zeros(); + + if context.collider_handle1 == self.platform1 { + allowed_local_n1 = Vector3::y(); + } else if context.collider_handle2 == self.platform1 { + // Flip the allowed direction. + allowed_local_n1 = -Vector3::y(); + } + + if context.collider_handle1 == self.platform2 { + allowed_local_n1 = -Vector3::y(); + } else if context.collider_handle2 == self.platform2 { + // Flip the allowed direction. + allowed_local_n1 = -Vector3::y(); + } + + // Call the helper function that simulates one-way platforms. + context.update_as_oneway_platform(&allowed_local_n1, 0.1); + + // Set the surface velocity of the accepted contacts. + let tangent_velocity = if context.collider_handle1 == self.platform1 + || context.collider_handle2 == self.platform2 + { + -12.0 + } else { + 12.0 + }; + + for contact in context.solver_contacts.iter_mut() { + contact.tangent_velocity.z = tangent_velocity; + } + } +} + +pub fn init_world(testbed: &mut Testbed) { + /* + * World + */ + let mut bodies = RigidBodySet::new(); + let mut colliders = ColliderSet::new(); + let joints = JointSet::new(); + + /* + * Ground + */ + let rigid_body = RigidBodyBuilder::new_static().build(); + let handle = bodies.insert(rigid_body); + + let collider = ColliderBuilder::cuboid(9.0, 0.5, 25.0) + .translation(0.0, 2.0, 30.0) + .modify_solver_contacts(true) + .build(); + let platform1 = colliders.insert(collider, handle, &mut bodies); + let collider = ColliderBuilder::cuboid(9.0, 0.5, 25.0) + .translation(0.0, -2.0, -30.0) + .modify_solver_contacts(true) + .build(); + let platform2 = colliders.insert(collider, handle, &mut bodies); + + /* + * Setup the one-way platform hook. + */ + let physics_hooks = OneWayPlatformHook { + platform1, + platform2, + }; + + /* + * Spawn cubes at regular intervals and apply a custom gravity + * depending on their position. + */ + testbed.add_callback(move |mut window, mut graphics, physics, _, run_state| { + if run_state.timestep_id % 50 == 0 && physics.bodies.len() <= 7 { + // Spawn a new cube. + let collider = ColliderBuilder::cuboid(1.0, 2.0, 1.5).build(); + let body = RigidBodyBuilder::new_dynamic() + .translation(0.0, 6.0, 20.0) + .build(); + let handle = physics.bodies.insert(body); + physics + .colliders + .insert(collider, handle, &mut physics.bodies); + + if let (Some(graphics), Some(window)) = (&mut graphics, &mut window) { + graphics.add(window, handle, &physics.bodies, &physics.colliders); + } + } + + physics.bodies.foreach_active_dynamic_body_mut(|_, body| { + if body.position().translation.y > 1.0 { + body.set_gravity_scale(1.0, false); + } else if body.position().translation.y < -1.0 { + body.set_gravity_scale(-1.0, false); + } + }); + }); + + /* + * Set up the testbed. + */ + testbed.set_world_with_params( + bodies, + colliders, + joints, + Vector3::new(0.0, -9.81, 0.0), + physics_hooks, + ); + testbed.look_at(Point3::new(-100.0, 0.0, 0.0), Point3::origin()); +} + +fn main() { + let testbed = Testbed::from_builders(0, vec![("Boxes", init_world)]); + testbed.run() +} |
