Rust 2D碰撞检测库parry2d-f64的使用,高性能几何计算与物理引擎集成
Rust 2D碰撞检测库parry2d-f64的使用,高性能几何计算与物理引擎集成
Parry 是一套2D和3D几何与碰撞检测库,包括 parry2d, parry3d, parry2d-f64 和 parry3d-f64。这些库由 Dimforge 组织使用Rust编程语言开发,完全免费且开源!
安装
在您的项目目录中运行以下Cargo命令:
cargo add parry2d-f64
或者在您的Cargo.toml中添加以下行:
parry2d-f64 = "0.22.0"
示例代码
下面是一个使用parry2d-f64进行2D碰撞检测的完整示例:
use parry2d_f64::{
shape::{Ball, Cuboid},
math::{Isometry, Vector},
query::{self, Contact},
};
fn main() {
// 创建一个球体和一个立方体
let ball = Ball::new(1.0);
let cube = Cuboid::new(Vector::new(1.0, 1.0));
// 设置它们的位置
let ball_pos = Isometry::translation(2.0, 0.0);
let cube_pos = Isometry::identity();
// 检测碰撞
if let Some(contact) = query::contact(&ball_pos, &ball, &cube_pos, &cube, 0.0) {
println!("碰撞检测结果:");
println!("碰撞点: {:?}", contact.point);
println!("碰撞法线: {:?}", contact.normal);
println!("穿透深度: {:?}", contact.depth);
} else {
println!("没有检测到碰撞");
}
// 检测距离
let distance = query::distance(&ball_pos, &ball, &cube_pos, &cube);
println!("两者之间的距离: {}", distance);
}
物理引擎集成示例
下面是一个更完整的示例,展示如何将parry2d-f64与物理引擎集成:
use parry2d_f64::{
shape::{Ball, Cuboid},
math::{Isometry, Vector},
query::{self, Contact},
na::Point2,
};
struct PhysicsBody {
shape: Box<dyn parry2d_f64::shape::Shape>,
position: Isometry<f64>,
velocity: Vector<f64>,
mass: f64,
}
fn main() {
// 创建物理世界中的两个物体
let mut bodies = vec![
PhysicsBody {
shape: Box::new(Ball::new(1.0)),
position: Isometry::translation(0.0, 0.0),
velocity: Vector::new(1.0, 0.0),
mass: 1.0,
},
PhysicsBody {
shape: Box::new(Cuboid::new(Vector::new(1.0, 1.0))),
position: Isometry::translation(5.0, 0.0),
velocity: Vector::new(0.0, 0.0),
mass: 2.0,
},
];
// 模拟物理世界
for _ in 0..100 {
// 更新位置
for body in &mut bodies {
body.position.translation.vector += body.velocity * 0.016; // 16ms时间步长
}
// 检测碰撞
for i in 0..bodies.len() {
for j in i+1..bodies.len() {
if let Some(contact) = query::contact(
&bodies[i].position,
bodies[i].shape.as_ref(),
&bodies[j].position,
bodies[j].shape.as_ref(),
0.0
) {
println!("物体 {} 和 {} 发生碰撞", i, j);
handle_collision(&mut bodies[i], &mut bodies[j], contact);
}
}
}
}
}
fn handle_collision(body1: &mut PhysicsBody, body2: &mut PhysicsBody, contact: Contact) {
// 简化的碰撞响应 - 交换速度
let temp_vel = body1.velocity;
body1.velocity = body2.velocity;
body2.velocity = temp_vel;
}
这个示例展示了如何:
- 创建基本的物理物体
- 更新它们的运动
- 检测碰撞
- 处理碰撞响应
您可以根据需要扩展这个基础框架,添加更复杂的物理特性如摩擦力、旋转、力矩等。
完整示例DEMO
下面是一个更完整的2D物理引擎示例,包含了碰撞检测、物理模拟和简单的渲染:
use parry2d_f64::{
math::{Isometry, Vector},
na::Point2,
query::{self, Contact},
shape::{Ball, Cuboid, Shape},
};
use std::f64::consts::PI;
// 物理物体结构体
struct PhysicsBody {
shape: Box<dyn Shape>,
position: Isometry<f64>,
velocity: Vector<f64>,
angular_velocity: f64,
mass: f64,
restitution: f64, // 弹性系数
}
// 物理世界结构体
struct PhysicsWorld {
bodies: Vec<PhysicsBody>,
gravity: Vector<f64>,
}
impl PhysicsWorld {
fn new() -> Self {
PhysicsWorld {
bodies: Vec::new(),
gravity: Vector::new(0.0, -9.81),
}
}
fn add_body(&mut self, body: PhysicsBody) {
self.bodies.push(body);
}
fn step(&mut self, dt: f64) {
// 应用重力并更新位置
for body in &mut self.bodies {
body.velocity += self.gravity * dt;
body.position.translation.vector += body.velocity * dt;
body.position.rotation = body.position.rotation
.rotate(body.angular_velocity * dt);
}
// 碰撞检测和响应
for i in 0..self.bodies.len() {
for j in i + 1..self.bodies.len() {
if let Some(contact) = query::contact(
&self.bodies[i].position,
self.bodies[i].shape.as_ref(),
&self.bodies[j].position,
self.bodies[j].shape.as_ref(),
0.0,
) {
self.resolve_collision(i, j, contact);
}
}
}
}
fn resolve_collision(&mut self, i: usize, j: usize, contact: Contact) {
// 更真实的碰撞响应
let body1 = &mut self.bodies[i];
let body2 = &mut self.bodies[j];
let relative_velocity = body2.velocity - body1.velocity;
let velocity_along_normal = relative_velocity.dot(&contact.normal);
// 如果物体正在分离,不需要处理碰撞
if velocity_along_normal > 0.0 {
return;
}
// 计算冲量
let restitution = body1.restitution.min(body2.restitution);
let mut impulse_magnitude = -(1.0 + restitution) * velocity_along_normal;
impulse_magnitude /= 1.0 / body1.mass + 1.0 / body2.mass;
let impulse = contact.normal * impulse_magnitude;
// 应用冲量
body1.velocity -= impulse / body1.mass;
body2.velocity += impulse / body2.mass;
// 简单的位置修正以避免物体重叠
let correction = contact.normal * contact.depth * 0.2;
body1.position.translation.vector -= correction / body1.mass;
body2.position.translation.vector += correction / body2.mass;
}
}
fn main() {
let mut world = PhysicsWorld::new();
// 添加一个静态地面
world.add_body(PhysicsBody {
shape: Box::new(Cuboid::new(Vector::new(10.0, 0.5))),
position: Isometry::translation(0.0, -5.0),
velocity: Vector::zeros(),
angular_velocity: 0.0,
mass: f64::INFINITY, // 无限质量表示静态物体
restitution: 0.5,
});
// 添加一些动态物体
for i in 0..5 {
world.add_body(PhysicsBody {
shape: if i % 2 == 0 {
Box::new(Ball::new(0.5))
} else {
Box::new(Cuboid::new(Vector::new(0.5, 0.5)))
},
position: Isometry::translation(i as f64 * 1.5 - 3.0, 5.0),
velocity: Vector::new(0.0, 0.0),
angular_velocity: if i % 2 == 0 { 0.0 } else { PI / 4.0 },
mass: 1.0,
restitution: 0.7,
});
}
// 模拟1000步
for step in 0..1000 {
world.step(0.016); // 16ms时间步长
// 每100步打印一次状态
if step % 100 == 0 {
println!("Step {}", step);
for (i, body) in world.bodies.iter().enumerate() {
println!(
"Body {}: position = {:?}, velocity = {:?}",
i, body.position.translation.vector, body.velocity
);
}
println!();
}
}
}
这个完整示例展示了:
- 创建物理世界和物体
- 处理重力、速度和位置更新
- 更真实的碰撞响应(包含弹性和冲量计算)
- 支持圆形和矩形两种形状
- 静态物体和动态物体的区分
- 简单的模拟状态输出
您可以通过添加更多物理特性来扩展这个示例,如摩擦力、空气阻力、关节约束等。
1 回复
Rust 2D碰撞检测库parry2d-f64使用指南
介绍
parry2d-f64是一个高性能的2D碰撞检测库,专注于几何计算和物理引擎集成。它是parry物理引擎生态系统的一部分,专门针对2D场景进行了优化,使用f64浮点精度进行计算。
主要特性
- 支持多种基本几何形状的碰撞检测(圆形、矩形、多边形等)
- 精确的接触点计算
- 距离查询
- 时间碰撞检测(CCD)
- 高性能的broad-phase和narrow-phase算法
- 与Rust物理引擎(如Rapier)兼容
完整示例代码
use parry2d::shape::{Ball, Cuboid};
use parry2d::query::{self, ShapeQuery};
use parry2d::math::{Isometry, Vector};
use parry2d::partitioning::{DBVT, DBVTLeaf};
fn main() {
// 1. 创建几何形状
println!("=== 创建几何形状 ===");
let ball = Ball::new(5.0); // 半径5.0的圆形
let cuboid = Cuboid::new(Vector::new(2.0, 3.0)); // 半边长x=2.0, y=3.0的矩形
// 2. 碰撞检测
println!("\n=== 碰撞检测 ===");
let pos1 = Isometry::new(Vector::new(1.0, 2.0), 0.0); // 位置和旋转
let pos2 = Isometry::new(Vector::new(3.0, 2.0), 0.0);
// 检测碰撞
let intersects = query::intersection_test(&pos1, &ball, &pos2, &cuboid).unwrap();
println!("是否碰撞: {}", intersects);
// 计算接触点
let contact = query::contact(&pos1, &ball, &pos2, &cuboid, 0.0).unwrap();
if let Some(contact) = contact {
println!("接触点: {:?}", contact.point);
println!("接触法线: {:?}", contact.normal);
println!("穿透深度: {}", contact.dist);
}
// 3. 距离查询
println!("\n=== 距离查询 ===");
let distance = query::distance(&pos1, &ball, &pos2, &cuboid).unwrap();
println!("两个形状之间的距离: {}", distance);
// 计算最近点
let closest_points = query::closest_points(&pos1, &ball, &pos2, &cuboid, 10.0).unwrap();
match closest_points {
query::ClosestPoints::Intersecting => println!("形状相交"),
query::ClosestPoints::WithinMargin(p1, p2) => {
println!("最近点1: {:?}", p1);
println!("最近点2: {:?}", p2);
}
query::ClosestPoints::Disjoint => println!("形状不相交且距离超过阈值"),
}
// 4. 时间碰撞检测(CCD)
println!("\n=== 时间碰撞检测 ===");
let vel1 = Vector::new(1.0, 0.0);
let vel2 = Vector::new(-1.0, 0.0);
let toi = query::time_of_impact(
&pos1,
&vel1,
&ball,
&pos2,
&vel2,
&cuboid,
std::f64::MAX,
true,
).unwrap();
if let Some(toi) = toi {
println!("碰撞将在 {} 秒后发生", toi.toi);
println!("碰撞时的位置: {:?}", toi.witness1);
} else {
println!("不会发生碰撞");
}
// 5. 性能优化 - BroadPhase
println!("\n=== 性能优化 ===");
let mut dbvt = DBVT::new();
let aabb = ball.compute_aabb(&pos1);
dbvt.insert(DBVTLeaf::new(aabb, 0)); // 0是物体ID
println!("创建DBVT用于粗检测");
// 6. 重用查询对象
let mut contact_manifold = query::ContactManifold::new();
query::contact_manifolds(
&pos1,
&ball,
&pos2,
&cuboid,
&mut contact_manifold,
false,
);
println!("重用ContactManifold减少内存分配");
}
示例说明
这个完整示例展示了parry2d-f64库的主要功能:
- 创建几何形状:创建圆形和矩形两种基本形状
- 碰撞检测:检测两个形状是否相交,并计算接触点信息
- 距离查询:计算两个形状之间的距离和最近点
- 时间碰撞检测:预测未来可能发生的碰撞
- 性能优化:使用DBVT进行粗检测和重用查询对象
运行此代码需要先在Cargo.toml中添加依赖:
[dependencies]
parry2d = { version = "0.13", features = ["f64"] }
nalgebra = "0.32" # 用于向量和矩阵运算
总结
parry2d-f64提供了强大的2D碰撞检测功能,这个完整示例展示了其主要API的使用方法。通过合理使用这些功能,可以构建出高效可靠的碰撞检测系统。