dimforge / rapier

2D and 3D physics engines focused on performance.
https://rapier.rs
Apache License 2.0
3.91k stars 244 forks source link

No collision after several interaction #283

Closed dmvict closed 2 years ago

dmvict commented 2 years ago

I wrote simple program that represents issue.

The collisions of dynamic body with static body after several interaction are disappeared.

use anyhow::Result;
use macroquad::prelude::*;
use rapier3d::prelude::*;

#[macroquad::main("sample")]
async fn main() -> Result<()> {
    let start_xd = 200.0;
    let start_yd = 200.0;
    let start_xs = 100.0;
    let start_ys = start_yd;
    let rect_size = 10.0;

    let mut rigid_body_set = RigidBodySet::new();
    let mut collider_set = ColliderSet::new();

    // static rectangle
    let rigid_body = RigidBodyBuilder::new_static()
        .translation(vector![start_xs, start_ys, 0.0])
        .ccd_enabled(true)
        .build();
    let collider = ColliderBuilder::cuboid(rect_size, rect_size, rect_size).build();
    let body_handle = rigid_body_set.insert(rigid_body);
    collider_set.insert_with_parent(collider, body_handle, &mut rigid_body_set);

    // dynamic rectangle
    let rigid_body = RigidBodyBuilder::new_dynamic()
        .translation(vector![start_xd, start_yd, 0.0])
        .ccd_enabled(true)
        .build();
    let collider = ColliderBuilder::cuboid(rect_size, rect_size, rect_size)
        .restitution(0.7)
        .build();
    let body_handle = rigid_body_set.insert(rigid_body);
    collider_set.insert_with_parent(collider, body_handle, &mut rigid_body_set);

    // setup rapier3d
    let gravity = vector![0.0, 0.0, 0.0];
    let integration_parameters = IntegrationParameters::default();
    let mut physics_pipeline = PhysicsPipeline::new();
    let mut island_manager = IslandManager::new();
    let mut broad_phase = BroadPhase::new();
    let mut narrow_phase = NarrowPhase::new();
    let mut joint_set = JointSet::new();
    let mut ccd_solver = CCDSolver::new();
    let physics_hooks = ();
    let event_handler = ();

    loop {
        clear_background(LIGHTGRAY);

        let speed = 1.0;
        let mut moving_delta = Vec2::new(0., 0.);
        if is_key_down(KeyCode::Right) || is_key_down(KeyCode::D) {
            moving_delta.x = speed;
        }
        if is_key_down(KeyCode::Left) || is_key_down(KeyCode::A) {
            moving_delta.x = -speed;
        }
        if is_key_down(KeyCode::Down) || is_key_down(KeyCode::S) {
            moving_delta.y = speed;
        }
        if is_key_down(KeyCode::Up) || is_key_down(KeyCode::W) {
            moving_delta.y = -speed;
        }

        {
            let body = &mut rigid_body_set[body_handle];
            body.apply_impulse(vector!(moving_delta.x * 2000.0, moving_delta.y * 2000.0, 0.0), true);
        }

        physics_pipeline.step(
            &gravity,
            &integration_parameters,
            &mut island_manager,
            &mut broad_phase,
            &mut narrow_phase,
            &mut rigid_body_set,
            &mut collider_set,
            &mut joint_set,
            &mut ccd_solver,
            &physics_hooks,
            &event_handler,
        );

        if is_key_down(KeyCode::Escape) {
            break;
        }

        let body = &rigid_body_set[body_handle];
        let tr = body.translation();

        draw_rectangle(start_xs, start_ys, rect_size * 2.0, rect_size * 2.0, GREEN);
        draw_rectangle(tr.x, tr.y, rect_size * 2.0, rect_size * 2.0, GRAY);
        next_frame().await;
    }

    Ok(())
}

What is wrong with the sample? How to keep collisions?

sebcrozet commented 2 years ago

Hi! You are using a 3D physics engine for performing a 2D simulation. So keep in mind that:

  1. The object may move along the z axis, in such a way that it is no longer collides with the other objects (but you don’t see it on the screen because you are rendering a 2D projection of the scene).
  2. The dynamic body may rotate, so it can reach an orientation that doesn’t match the orientation you are rendering. So it may enter a configuration where there is no actual collision despite what you are seeing because se rendering is wrong by ignoring rotations.

You probably want to:

  1. Switch to rapier2d instead of rapier3d.
  2. And take rotations into account for your rendering, or lock the rotations of your dynamic rigid-body if you don’t want that body to rotate.
dmvict commented 2 years ago

@sebcrozet, thank you for the answer.

I'll implement this features.