为什么在这个简单的例子中垂直速度趋向于零?

问题描述 投票:0回答:1

我有 4 个完美弹性的墙,排列成一个盒子,还有一个零重力下的完美弹性球。球的初始速度为

(100., 100.)
,并且应该永远在盒子的四个边界之间弹跳。

然而,由于某种未知的原因,速度的 y 分量在每次弹跳后都趋向于零,直到最终,它只是从左右墙壁弹起,根本没有垂直速度。

这是我的代码的最小工作示例:

use rapier2d::prelude as rapier;
use macroquad::prelude as mq;

struct PhysicsWorld {
    gravity: rapier::Vector<f32>,
    integration_parameters: rapier::IntegrationParameters,
    pipeline: rapier::PhysicsPipeline,
    island_manager: rapier::IslandManager,
    broad_phase: rapier::BroadPhase,
    narrow_phase: rapier::NarrowPhase,
    rigid_body_set: rapier::RigidBodySet,
    collider_set: rapier::ColliderSet,
    impulse_joint_set: rapier::ImpulseJointSet,
    multibody_joint_set: rapier::MultibodyJointSet,
    ccd_solver: rapier::CCDSolver,
    query_pipeline: rapier::QueryPipeline,
    physics_hooks: (),
    event_handler: (),
}

impl Default for PhysicsWorld {
    fn default() -> Self {
        let gravity = rapier::Vector::zeros();
        let integration_parameters = rapier::IntegrationParameters{
            num_solver_iterations: std::num::NonZeroUsize::new(16).unwrap(),
            prediction_distance: 0.001,
            ..Default::default()
        
        };
        let pipeline = rapier::PhysicsPipeline::new();
        let island_manager = rapier::IslandManager::new();
        let broad_phase = rapier::BroadPhase::new();
        let narrow_phase = rapier::NarrowPhase::new();
        let rigid_body_set = rapier::RigidBodySet::new();
        let collider_set = rapier::ColliderSet::new();
        let impulse_joint_set = rapier::ImpulseJointSet::new();
        let multibody_joint_set = rapier::MultibodyJointSet::new();
        let ccd_solver = rapier::CCDSolver::new();
        let query_pipeline = rapier::QueryPipeline::new();
        let physics_hooks = ();
        let event_handler = ();
        Self {
            gravity,
            integration_parameters,
            pipeline,
            island_manager,
            broad_phase,
            narrow_phase,
            rigid_body_set,
            collider_set,
            impulse_joint_set,
            multibody_joint_set,
            ccd_solver,
            query_pipeline,
            physics_hooks,
            event_handler,
        }
    }
}

impl PhysicsWorld {
    fn update(&mut self) {
        self.pipeline.step(
            &self.gravity,
            &self.integration_parameters,
            &mut self.island_manager,
            &mut self.broad_phase,
            &mut self.narrow_phase,
            &mut self.rigid_body_set,
            &mut self.collider_set,
            &mut self.impulse_joint_set,
            &mut self.multibody_joint_set,
            &mut self.ccd_solver,
            Some(&mut self.query_pipeline),
            &self.physics_hooks,
            &self.event_handler,
        );
    }

    pub fn add_ball_with_velocity(&mut self, radius: f32, x: f32, y: f32, vx: f32, vy: f32) -> (rapier::RigidBodyHandle, rapier::ColliderHandle) {
        let rigid_body = rapier::RigidBodyBuilder::dynamic().translation(rapier::vector![x, y]).linvel(rapier::vector![vx, vy]).build();
        let collider = rapier::ColliderBuilder::ball(radius).restitution(1.0).build();        
        let ball_r_handle = self.rigid_body_set.insert(rigid_body);
        let ball_c_handle = self.collider_set.insert_with_parent(collider, ball_r_handle, &mut self.rigid_body_set);
        return (ball_r_handle, ball_c_handle);
    }

    pub fn add_fixed_cuboid(&mut self, x: f32, y: f32, hx: f32, hy: f32) -> (rapier::RigidBodyHandle, rapier::ColliderHandle) {
        let rigid_body = rapier::RigidBodyBuilder::fixed().translation(rapier::vector![x, y]).build();
        let collider = rapier::ColliderBuilder::cuboid(hx, hy).restitution(1.0).build();
        let cuboid_r_handle = self.rigid_body_set.insert(rigid_body);
        let cuboid_c_handle = self.collider_set.insert_with_parent(collider, cuboid_r_handle, &mut self.rigid_body_set);
        return (cuboid_r_handle, cuboid_c_handle);
    }

    pub fn add_window_borders(&mut self) {
        let width = mq::screen_width();
        let height = mq::screen_height();
        let thickness = 10.0;
        let h_center_x = width / 2.0;
        let v_center_y = height / 2.0;
        let h_top_y = height - thickness / 2.0; //(center of top border)
        let h_bottom_y = thickness / 2.0; //(center of bottom border)
        let v_left_x = thickness / 2.0; //(center of left border)
        let v_right_x = width - thickness / 2.0; //(center of right border)
        let _top = self.add_fixed_cuboid(h_center_x, h_top_y, width / 2.0, thickness / 2.0);
        let _bottom = self.add_fixed_cuboid(h_center_x, h_bottom_y, width / 2.0, thickness / 2.0);
        let _left = self.add_fixed_cuboid(v_left_x, v_center_y, thickness / 2.0, height / 2.0);
        let _right = self.add_fixed_cuboid(v_right_x, v_center_y, thickness / 2.0, height / 2.0);
    }

    //draw the colliders (using the rigid body they are attached to)
    pub fn draw_colliders(&self) {
        for (_handle, collider) in self.collider_set.iter() {
            let rigid_body_handle = collider.parent().expect("Collider has no parent");
            let body = self.rigid_body_set.get(rigid_body_handle).unwrap();
            let pos = body.position().translation.vector;
            let shape: &dyn rapier::Shape = collider.shape();
            match (shape.as_ball(), shape.as_cuboid()) {
                (Some(ball), None) => {
                    mq::draw_circle(pos.x, pos.y, ball.radius, mq::WHITE);
                }
                (None, Some(cuboid)) => {
                    mq::draw_rectangle(pos.x - cuboid.half_extents.x, pos.y - cuboid.half_extents.y, cuboid.half_extents.x * 2.0, cuboid.half_extents.y * 2.0, mq::WHITE);
                }
                _ => {unreachable!()}
            }
        }
    }

    pub fn draw_ball_velocity_vector(&self, handle: rapier::RigidBodyHandle) {
        let body = self.rigid_body_set.get(handle).unwrap();
        let vel = body.linvel();
        mq::draw_text(&format!("vx: {:.2}, vy: {:.2}", vel.x, vel.y), 10., 30., 20.0, mq::WHITE);
    }
}

const ASPECT_RATIO: f32 = 16.0 / 9.0;
const WINDOW_WIDTH: f32 = 300.0;
const WINDOW_HEIGHT: f32 = WINDOW_WIDTH * ASPECT_RATIO;

fn main() {
    macroquad::Window::from_config(
        mq::Conf {
            window_width: WINDOW_WIDTH as i32,
            window_height: WINDOW_HEIGHT as i32,
            ..Default::default()
        },
        amain(),
    );
}


async fn amain() {
    let mut world = PhysicsWorld::default();
    let (ball, _) = world.add_ball_with_velocity(10.0, 200.0, 200.0, 100.0, 100.0);
    world.add_window_borders();
    loop {
        world.update();
        mq::clear_background(mq::BLACK);   
        world.draw_ball_velocity_vector(ball);     
        world.draw_colliders();
        mq::next_frame().await
    }
}

为什么会出现这种情况?是什么导致球失去其速度的 y 分量?我该如何解决它?

rust game-physics rapier rapier-2d
1个回答
0
投票

我需要将对撞机和球的摩擦力设置为零。

pub fn add_ball_with_velocity(&mut self, radius: f32, x: f32, y: f32, vx: f32, vy: f32) -> (rapier::RigidBodyHandle, rapier::ColliderHandle) {
    let rigid_body = rapier::RigidBodyBuilder::dynamic()
    .translation(rapier::vector![x, y])
    .linvel(rapier::vector![vx, vy])
    .lock_rotations()
    .build();
    let collider = rapier::ColliderBuilder::ball(radius)
    .restitution(1.0)
    .friction(0.)
    .build();        
    let ball_r_handle = self.rigid_body_set.insert(rigid_body);
    let ball_c_handle = self.collider_set.insert_with_parent(collider, ball_r_handle, &mut self.rigid_body_set);
    return (ball_r_handle, ball_c_handle);
}

pub fn add_fixed_cuboid(&mut self, x: f32, y: f32, hx: f32, hy: f32) -> (rapier::RigidBodyHandle, rapier::ColliderHandle) {
    let rigid_body = rapier::RigidBodyBuilder::fixed()
    .translation(rapier::vector![x, y])
    .build();
    let collider = rapier::ColliderBuilder::cuboid(hx, hy)
    .restitution(1.0)
    .friction(0.)
    .build();
    let cuboid_r_handle = self.rigid_body_set.insert(rigid_body);
    let cuboid_c_handle = self.collider_set.insert_with_parent(collider, cuboid_r_handle, &mut self.rigid_body_set);
    return (cuboid_r_handle, cuboid_c_handle);
}
© www.soinside.com 2019 - 2024. All rights reserved.