Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to fix shaking collisions? #793

Open
historydev opened this issue Jan 28, 2025 · 0 comments
Open

How to fix shaking collisions? #793

historydev opened this issue Jan 28, 2025 · 0 comments

Comments

@historydev
Copy link

historydev commented Jan 28, 2025

I modified the basic example a bit to try and handle collisions between circles, using interpolation and fixed step I couldn't fix it.

  • What did I do wrong and how can I fix it?

I'm using macroquad for rendering:

use macroquad::camera::{set_camera, Camera2D};
use macroquad::color::{GREEN, PURPLE};
use macroquad::input::{
    is_key_pressed, is_mouse_button_down, is_mouse_button_pressed, mouse_position, MouseButton,
};
use macroquad::math::vec2;
use macroquad::prelude::{clear_background, get_frame_time, next_frame, WHITE};
use macroquad::shapes::{draw_circle, draw_rectangle};
use macroquad::window::{screen_height, screen_width};
use rapier2d::na::Vector2;
use rapier2d::prelude::*;

const FIXED_TIMESTEP: f32 = 1.0 / 60.0;

fn add_ball(
    rigid_body_set: &mut RigidBodySet,
    collider_set: &mut ColliderSet,
    translation: Vector2<f32>,
    radius: f32,
    restitution: f32,
) {
    let rigid_body = RigidBodyBuilder::dynamic()
        .translation(translation)
        // .gravity_scale(0.0)
        .ccd_enabled(true)
        .linear_damping(0.1)
        .build();
    let ball_body_handle = rigid_body_set.insert(rigid_body);

    let collider = ColliderBuilder::ball(radius)
        .restitution(restitution)
        .build();
    let collider_handle = collider_set.insert_with_parent(collider, ball_body_handle, rigid_body_set);
    if let Some(collider) = collider_set.get_mut(collider_handle) {
        collider.set_friction_combine_rule(CoefficientCombineRule::Min);
        collider.set_restitution_combine_rule(CoefficientCombineRule::Min);
    }
}

pub async fn physics5() {
    let mut rigid_body_set = RigidBodySet::new();
    let mut collider_set = ColliderSet::new();

    /* Create the ground. */
    let collider = ColliderBuilder::cuboid(100.0, 50.)
        .translation(vector![0.0, 200.0])
        .build();
    let collider_handle = collider_set.insert(collider);

    let restitution = 1.0;
    let radius = 100.;

    add_ball(
        &mut rigid_body_set,
        &mut collider_set,
        vector![0.0, 0.0],
        radius,
        restitution,
    );
    add_ball(
        &mut rigid_body_set,
        &mut collider_set,
        vector![-50.0, -100.0],
        radius,
        restitution,
    );
    add_ball(
        &mut rigid_body_set,
        &mut collider_set,
        vector![-300.0, -300.0],
        radius,
        restitution,
    );

    /* Create other structures necessary for the simulation. */
    let mut gravity = vector![0.0, 1000.];
    let integration_parameters = IntegrationParameters::default();
    let mut physics_pipeline = PhysicsPipeline::new();
    let mut island_manager = IslandManager::new();
    let mut broad_phase = DefaultBroadPhase::new();
    let mut narrow_phase = NarrowPhase::new();
    let mut impulse_joint_set = ImpulseJointSet::new();
    let mut multibody_joint_set = MultibodyJointSet::new();
    let mut ccd_solver = CCDSolver::new();
    let mut query_pipeline = QueryPipeline::new();
    let physics_hooks = ();
    let event_handler = ();

    let mut camera = Camera2D::default();
    let mut accumulator = 0.0;

    let mut old_positions: HashMap<RigidBodyHandle, Vector2<f32>> = HashMap::new();

    loop {
        accumulator += get_frame_time();

        if is_mouse_button_down(MouseButton::Left) {
            gravity[1] = -1000.;
        } else {
            gravity[1] = 1000.;
        }

        if is_mouse_button_down(MouseButton::Middle) {
            gravity = vector![0., 0.];

            for (handle, body) in rigid_body_set.iter_mut() {
                body.set_translation(vector![0., 0.], true);
            }
        }

        while accumulator > FIXED_TIMESTEP {

            for (handle, body) in rigid_body_set.iter_mut() {
                let mouse = camera.screen_to_world(vec2(mouse_position().0, mouse_position().1));
                let direction_to_mouse = (mouse - vec2(body.translation().x, body.translation().y)).clamp_length_max(100.);

                old_positions.insert(handle, *body.translation());

                body.set_linvel(vector![direction_to_mouse.x, direction_to_mouse.y], true);
            }

            physics_pipeline.step(
                &gravity,
                &integration_parameters,
                &mut island_manager,
                &mut broad_phase,
                &mut narrow_phase,
                &mut rigid_body_set,
                &mut collider_set,
                &mut impulse_joint_set,
                &mut multibody_joint_set,
                &mut ccd_solver,
                Some(&mut query_pipeline),
                &physics_hooks,
                &event_handler,
            );

            accumulator -= FIXED_TIMESTEP;
        }

        camera.zoom = vec2(2.0 / screen_width(), 2.0 / screen_height());
        camera.target = vec2(0., 0.);

        set_camera(&camera);

        clear_background(WHITE);

        let rect_collider = &collider_set[collider_handle];
        let rect_pos = rect_collider.translation();

        draw_rectangle(rect_pos.x - 100., rect_pos.y - 50., 200., 100., GREEN);

        let alpha = accumulator / FIXED_TIMESTEP;

        for (ball_handle, ball_body) in rigid_body_set.iter_mut() {
            let old_pos = old_positions.get(&ball_handle).unwrap_or(&ball_body.translation());
            let curr_pos = ball_body.translation();
            let interpolated_pos = old_pos.lerp(curr_pos, alpha);

            // ball_body.add_force(vector![direction_to_mouse.x, direction_to_mouse.y] * 100., true);
            draw_circle(interpolated_pos.x, interpolated_pos.y, 100., PURPLE);
        }

        next_frame().await;
    }
}

#[macroquad::main("Playground")]
async fn main() {
    physics5().await;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant