Rust物理引擎库rapier2d的使用:高性能2D碰撞检测与刚体模拟的Rust实现

Rust物理引擎库rapier2d的使用:高性能2D碰撞检测与刚体模拟的Rust实现

crates.io

Rapier是一套用于游戏、动画和机器人技术的2D和3D物理引擎。这些库包括rapier2drapier3drapier2d-f64rapier3d-f64。它们由Rust编程语言编写,由Dimforge组织开发。它永远免费且开源!

什么是Rapier?

Rapier是一套用于游戏、动画和机器人技术的2D和3D物理引擎。

快速开始

使用Rapier的最简单方法是:

  1. 阅读用户指南
  2. 运行示例:cargo run --release --bin all_examples2cargo run --release --bin all_examples3
  3. 在Discord上寻求帮助,或在GitHub上提出问题

完整示例代码

use rapier2d::prelude::*;
use rapier2d::dynamics::RigidBodyBuilder;
use rapier2d::geometry::ColliderBuilder;

fn main() {
    // 初始化物理世界
    let gravity = vector![0.0, -9.81];
    let mut physics_pipeline = PhysicsPipeline::new();
    let mut integration_parameters = IntegrationParameters::default();
    let mut island_manager = IslandManager::new();
    let mut broad_phase = BroadPhase::new();
    let mut narrow_phase = NarrowPhase::new();
    let mut rigid_body_set = RigidBodySet::new();
    let mut collider_set = ColliderSet::new();
    let mut impulse_joint_set = ImpulseJointSet::new();
    let mut multibody_joint_set = MultibodyJointSet::new();

    // 创建地面
    let ground_size = 10.0;
    let ground_height = 0.1;
    
    let ground_rigid_body = RigidBodyBuilder::fixed()
        .translation(vector![0.0, -ground_height])
        .build();
    let ground_handle = rigid_body_set.insert(ground_rigid_body);
    
    let ground_collider = ColliderBuilder::cuboid(ground_size, ground_height)
        .build();
    collider_set.insert_with_parent(ground_collider, ground_handle, &mut rigid_body_set);

    // 创建一个下落的球体
    let ball_radius = 0.5;
    let ball_rigid_body = RigidBodyBuilder::dynamic()
        .translation(vector![0.0, 3.0])
        .build();
    let ball_handle = rigid_body_set.insert(ball_rigid_body);
    
    let ball_collider = ColliderBuilder::ball(ball_radius)
        .restitution(0.7) // 设置弹性系数
        .build();
    collider_set.insert_with_parent(ball_collider, ball_handle, &mut rigid_body_set);

    // 模拟100步物理
    for _ in 0..100 {
        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,
            &(),
            &(),
        );
        
        // 获取球体位置
        let ball = rigid_body_set.get(ball_handle).unwrap();
        println!("Ball position: ({}, {})", ball.translation().x, ball.translation().y);
    }
}

示例说明

  1. 首先创建物理世界,包括重力、碰撞检测等组件
  2. 创建一个固定的地面刚体和碰撞体
  3. 创建一个动态的球体刚体和碰撞体,并设置弹性系数
  4. 进行100步物理模拟,每步打印球体的位置

这个示例展示了Rapier的基本用法,包括:

  • 创建刚体(RigidBody)
  • 创建碰撞体(Collider)
  • 设置物理属性(如弹性系数)
  • 进行物理模拟

安装

在项目目录中运行以下Cargo命令:

cargo add rapier2d

或在Cargo.toml中添加:

rapier2d = "0.27.0"

类别

  • WebAssembly
  • 科学
  • 模拟
  • 游戏开发
  • 数学

扩展示例:多物体碰撞模拟

use rapier2d::prelude::*;
use rapier2d::dynamics::RigidBodyBuilder;
use rapier2d::geometry::ColliderBuilder;

fn main() {
    // 初始化物理世界
    let gravity = vector![0.0, -9.81];
    let mut physics_pipeline = PhysicsPipeline::new();
    let mut integration_parameters = IntegrationParameters::default();
    let mut island_manager = IslandManager::new();
    let mut broad_phase = BroadPhase::new();
    let mut narrow_phase = NarrowPhase::new();
    let mut rigid_body_set = RigidBodySet::new();
    let mut collider_set = ColliderSet::new();
    let mut impulse_joint_set = ImpulseJointSet::new();
    let mut multibody_joint_set = MultibodyJointSet::new();

    // 创建地面
    let ground_size = 20.0;
    let ground_height = 0.5;
    
    let ground_rigid_body = RigidBodyBuilder::fixed()
        .translation(vector![0.0, -ground_height])
        .build();
    let ground_handle = rigid_body_set.insert(ground_rigid_body);
    
    let ground_collider = ColliderBuilder::cuboid(ground_size, ground_height)
        .restitution(0.5)
        .friction(0.7)
        .build();
    collider_set.insert_with_parent(ground_collider, ground_handle, &mut rigid_body_set);

    // 创建多个随机下落的物体
    for i in 0..10 {
        let shape_type = i % 3;
        let radius = 0.3 + (i as f32 * 0.05) as f64;
        let x_pos = (i as f64 - 5.0) * 1.5;
        
        let body = RigidBodyBuilder::dynamic()
            .translation(vector![x_pos, 5.0 + i as f64 * 0.5])
            .build();
        let handle = rigid_body_set.insert(body);
        
        // 创建不同类型的碰撞体
        let collider = match shape_type {
            0 => ColliderBuilder::ball(radius),
            1 => ColliderBuilder::cuboid(radius, radius),
            _ => ColliderBuilder::capsule_y(radius, radius * 0.5),
        }
        .restitution(0.3 + i as f64 * 0.05)
        .friction(0.5)
        .build();
        
        collider_set.insert_with_parent(collider, handle, &mut rigid_body_set);
    }

    // 模拟200步物理
    for step in 0..200 {
        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,
            &(),
            &(),
        );
        
        // 每10步打印一次所有物体的位置
        if step % 10 == 0 {
            println!("Step {}", step);
            for (_, body) in rigid_body_set.iter() {
                println!("Object at: ({:.2}, {:.2})", 
                    body.translation().x, 
                    body.translation().y);
            }
        }
    }
}

这个扩展示例展示了:

  • 创建包含多种形状的物理场景
  • 设置不同的物理属性(弹性、摩擦系数)
  • 批量创建物体并管理它们
  • 更详细的模拟输出

您可以根据需要调整参数,如重力大小、物体数量、形状类型等,来创建不同的物理模拟场景。


1 回复

Rust物理引擎库rapier2d的使用:高性能2D碰撞检测与刚体模拟的Rust实现

以下是基于rapier2d的完整示例demo,展示了一个简单的物理模拟场景:

use rapier2d::prelude::*;
use std::f32::consts::PI;

fn main() {
    // 1. 初始化物理世界
    let gravity = vector![0.0, -9.81]; // 重力加速度
    let mut physics_pipeline = PhysicsPipeline::new();
    let integration_parameters = IntegrationParameters {
        dt: 1.0 / 60.0, // 每帧时间步长
        ..Default::default()
    };

    let mut physics_world = PhysicsWorld::new(gravity);
    let mut collider_set = ColliderSet::new();
    let mut rigid_body_set = RigidBodySet::new();
    let mut joint_set = JointSet::new();

    // 2. 创建地面(静态刚体)
    let ground_size = 50.0;
    let ground_pos = Isometry::translation(0.0, -10.0);
    let ground_shape = SharedShape::cuboid(ground_size, 1.0);
    let ground_collider = ColliderBuilder::new(ground_shape).build();
    collider_set.insert_with_parent(ground_collider, RigidBodyHandle::invalid(), &mut rigid_body_set);

    // 3. 创建动态刚体(球体)
    let ball_radius = 1.0;
    let ball_pos = Isometry::translation(0.0, 3.0);
    let ball_shape = SharedShape::ball(ball_radius);
    let ball_collider = ColliderBuilder::new(ball_shape)
        .restitution(0.7) // 弹性系数
        .friction(0.5)    // 摩擦系数
        .build();
    
    let ball_body = RigidBodyBuilder::dynamic()
        .translation(0.0, 3.0)
        .linvel(5.0, 0.0) // 初始水平速度
        .build();
    let ball_body_handle = rigid_body_set.insert(ball_body);
    collider_set.insert_with_parent(ball_collider, ball_body_handle, &mut rigid_body_set);

    // 4. 创建多边形刚体
    let poly_body = RigidBodyBuilder::dynamic()
        .translation(5.0, 5.0)
        .rotation(PI / 4.0) // 旋转45度
        .build();
    let poly_body_handle = rigid_body_set.insert(poly_body);
    
    let poly_points = [
        point![-1.0, -1.0],
        point![1.0, -1.0],
        point![1.0, 1.0],
        point![-1.0, 1.0],
    ];
    let poly_shape = SharedShape::convex_hull(&poly_points).unwrap();
    let poly_collider = ColliderBuilder::new(poly_shape)
        .restitution(0.3)
        .build();
    collider_set.insert_with_parent(poly_collider, poly_body_handle, &mut rigid_body_set);

    // 5. 模拟循环
    for _ in 0..300 {
        // 执行物理模拟
        physics_pipeline.step(
            &gravity,
            &integration_parameters,
            &mut physics_world,
            &mut collider_set,
            &mut rigid_body_set,
            &mut joint_set,
            &mut (),
            &mut (),
        );

        // 获取球体位置
        if let Some(ball_body) = rigid_body_set.get(ball_body_handle) {
            let position = ball_body.position();
            println!("Ball position: x={:.2}, y={:.2}", position.translation.x, position.translation.y);
        }

        // 碰撞检测
        let mut collision_events = Vec::new();
        physics_world.collision_events(&mut collision_events);
        
        for event in collision_events {
            match event {
                CollisionEvent::Started(h1, h2) => {
                    println!("碰撞开始: {:?} 和 {:?}", h1, h2);
                }
                CollisionEvent::Stopped(h1, h2) => {
                    println!("碰撞结束: {:?} 和 {:?}", h1, h2);
                }
            }
        }
    }
}

这个完整示例演示了:

  1. 初始化物理世界并设置重力
  2. 创建静态地面刚体
  3. 创建一个带有初始速度的动态球体
  4. 创建一个旋转的多边形刚体
  5. 运行300步物理模拟
  6. 每步输出球体位置
  7. 检测并输出碰撞事件

要运行此示例,请确保在Cargo.toml中添加了rapier2d依赖:

[dependencies]
rapier2d = "0.17"

这个示例展示了rapier2d的核心功能,包括刚体创建、碰撞检测和物理模拟。你可以根据需要扩展这个基础示例,添加更多刚体、关节或自定义碰撞行为。

回到顶部