dimforge / bevy_rapier

Official Rapier plugin for the Bevy game engine.
https://rapier.rs
Apache License 2.0
1.24k stars 260 forks source link

Inaccurate collisions when using a lot of `ColliderShape`s with the same height #124

Open daxpedda opened 2 years ago

daxpedda commented 2 years ago

When programming a simple platformer, building a straight path out of many ColliderShapes and having a character walk on it doesn't work.

I am assuming that the issue is that the y-coordinate of every ColliderShape is not exactly the same, because of f32 inaccuracies. So the character walks along the straight path but bumps into a block that isn't exactly on the same y-coordinate as the one before it.

Example code ```rust use bevy::prelude::*; use bevy_rapier2d::prelude::*; const SCALE: f32 = 16.; const PLATFORM_Y: f32 = -8.; const TILES: isize = 100; const CONTROLLER_JUMP_IMPULSE: f32 = 15.; fn main() { let mut app = App::new(); app.add_plugins(DefaultPlugins); app.add_plugin(RapierRenderPlugin); app.add_plugin(RapierPhysicsPlugin::::default()); app.add_startup_system(setup) .add_system(movement); app.run() } #[derive(Component)] struct Controller; fn setup(mut commands: Commands, mut rapier_config: ResMut) { commands .spawn() .insert_bundle(OrthographicCameraBundle::new_2d()); rapier_config.scale = SCALE; commands .spawn() .insert_bundle(RigidBodyBundle { mass_properties: RigidBodyMassPropsFlags::ROTATION_LOCKED.into(), ..Default::default() }) .insert_bundle(SpriteBundle { sprite: Sprite { color: Color::rgb(1., 0., 0.), custom_size: Some(Vec2::new(1. * SCALE, 2. * SCALE)), ..Default::default() }, ..Default::default() }) .insert_bundle(ColliderBundle { shape: ColliderShape::cuboid(0.5, 1.).into(), ..Default::default() }) .insert(ColliderPositionSync::Discrete).insert(Controller); for x in -TILES / 2..TILES / 2 { commands .spawn() .insert_bundle(SpriteBundle { sprite: Sprite { color: Color::rgb(0., 1., 0.), custom_size: Some(Vec2::new(1. * SCALE, 1. * SCALE)), ..Default::default() }, transform: Transform::from_xyz(x as f32 * SCALE, PLATFORM_Y * SCALE, 0.), ..Default::default() }) .insert_bundle(ColliderBundle { shape: ColliderShape::cuboid(0.5, 0.5).into(), position: [x as f32, PLATFORM_Y].into(), ..Default::default() }); } } fn movement( keyboard_input: Res>, mut controller: Query<( &mut RigidBodyForcesComponent, &mut RigidBodyVelocityComponent, &RigidBodyMassPropsComponent, &mut ColliderMaterialComponent, ), With>, ) { let (mut rb_forces, mut rb_vel, rb_mprops, mut co_material) = controller.single_mut(); if keyboard_input.just_pressed(KeyCode::Space) { rb_vel.apply_impulse(rb_mprops, Vec2::new(0., CONTROLLER_JUMP_IMPULSE).into()); } let mut x_axis = 0.; if keyboard_input.pressed(KeyCode::A) || keyboard_input.pressed(KeyCode::Left) { x_axis -= 1.; } else if keyboard_input.pressed(KeyCode::D) || keyboard_input.pressed(KeyCode::Right) { x_axis += 1.; } if x_axis == 0. { co_material.friction = 2.; } else { co_material.friction = 0.; x_axis *= 25. * rb_mprops.mass(); rb_forces.force.x = x_axis; } } ```

Somebody else had this issue before, probably with a better explanation of what the issue is about: https://dev.to/sbelzile/making-games-in-rust-part-7-fixing-the-player-randomly-stuck-issue-3mj5.

brandon-reinhart commented 2 years ago

I've run into this as well, but meshing all of the tiles is probably the right solution anyway. Still annoying that it blocks quick n' dirty tests.

Vrixyz commented 4 months ago

I think that's a rapier issue, but I agree it would be convenient to be able to have a smoother experience for "quick n' dirty tests".

Any update on reproduction code is appreciated.