rapier物理库
This commit is contained in:
181
pinball-physics/src/lib.rs
Normal file
181
pinball-physics/src/lib.rs
Normal file
@@ -0,0 +1,181 @@
|
||||
//! pinball-physics: 物理引擎库,同时支持原生 Rust 和 WASM 导出
|
||||
|
||||
use rapier2d::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// 物理世界包装器 - 原生 Rust API
|
||||
pub struct PhysicsWorld {
|
||||
gravity: Vector<Real>,
|
||||
integration_parameters: IntegrationParameters,
|
||||
physics_pipeline: PhysicsPipeline,
|
||||
island_manager: IslandManager,
|
||||
broad_phase: BroadPhase,
|
||||
narrow_phase: NarrowPhase,
|
||||
impulse_joint_set: ImpulseJointSet,
|
||||
multibody_joint_set: MultibodyJointSet,
|
||||
ccd_solver: CCDSolver,
|
||||
query_pipeline: QueryPipeline,
|
||||
rigid_body_set: RigidBodySet,
|
||||
collider_set: ColliderSet,
|
||||
body_map: HashMap<u32, RigidBodyHandle>,
|
||||
next_body_id: u32,
|
||||
}
|
||||
|
||||
impl PhysicsWorld {
|
||||
pub fn new(gravity_x: f32, gravity_y: f32) -> Self {
|
||||
PhysicsWorld {
|
||||
gravity: vector![gravity_x, gravity_y],
|
||||
integration_parameters: IntegrationParameters::default(),
|
||||
physics_pipeline: PhysicsPipeline::new(),
|
||||
island_manager: IslandManager::new(),
|
||||
broad_phase: BroadPhase::new(),
|
||||
narrow_phase: NarrowPhase::new(),
|
||||
impulse_joint_set: ImpulseJointSet::new(),
|
||||
multibody_joint_set: MultibodyJointSet::new(),
|
||||
ccd_solver: CCDSolver::new(),
|
||||
query_pipeline: QueryPipeline::new(),
|
||||
rigid_body_set: RigidBodySet::new(),
|
||||
collider_set: ColliderSet::new(),
|
||||
body_map: HashMap::new(),
|
||||
next_body_id: 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn step(&mut self) {
|
||||
self.physics_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),
|
||||
&(),
|
||||
&(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn create_dynamic_body(&mut self, x: f32, y: f32) -> u32 {
|
||||
let rb = RigidBodyBuilder::dynamic().translation(vector![x, y]).build();
|
||||
let handle = self.rigid_body_set.insert(rb);
|
||||
let id = self.next_body_id;
|
||||
self.next_body_id = self.next_body_id.wrapping_add(1);
|
||||
self.body_map.insert(id, handle);
|
||||
id
|
||||
}
|
||||
|
||||
pub fn create_static_body(&mut self, x: f32, y: f32) -> u32 {
|
||||
let rb = RigidBodyBuilder::fixed().translation(vector![x, y]).build();
|
||||
let handle = self.rigid_body_set.insert(rb);
|
||||
let id = self.next_body_id;
|
||||
self.next_body_id = self.next_body_id.wrapping_add(1);
|
||||
self.body_map.insert(id, handle);
|
||||
id
|
||||
}
|
||||
|
||||
pub fn add_circle_collider(&mut self, body_id: u32, radius: f32) {
|
||||
if let Some(&handle) = self.body_map.get(&body_id) {
|
||||
let collider = ColliderBuilder::ball(radius).build();
|
||||
self.collider_set.insert_with_parent(collider, handle, &mut self.rigid_body_set);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_box_collider(&mut self, body_id: u32, half_width: f32, half_height: f32) {
|
||||
if let Some(&handle) = self.body_map.get(&body_id) {
|
||||
let collider = ColliderBuilder::cuboid(half_width, half_height).build();
|
||||
self.collider_set.insert_with_parent(collider, handle, &mut self.rigid_body_set);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_body_position(&self, body_id: u32) -> Option<(f32, f32)> {
|
||||
if let Some(&handle) = self.body_map.get(&body_id) {
|
||||
if let Some(body) = self.rigid_body_set.get(handle) {
|
||||
let pos = body.translation();
|
||||
return Some((pos.x, pos.y));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn set_body_velocity(&mut self, body_id: u32, vx: f32, vy: f32) {
|
||||
if let Some(&handle) = self.body_map.get(&body_id) {
|
||||
if let Some(body) = self.rigid_body_set.get_mut(handle) {
|
||||
body.set_linvel(vector![vx, vy], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_impulse(&mut self, body_id: u32, ix: f32, iy: f32) {
|
||||
if let Some(&handle) = self.body_map.get(&body_id) {
|
||||
if let Some(body) = self.rigid_body_set.get_mut(handle) {
|
||||
body.apply_impulse(vector![ix, iy], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WASM C ABI 导出(当编译为 wasm32 时)
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod wasm_exports {
|
||||
use super::*;
|
||||
use std::sync::Mutex;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
type WorldId = u32;
|
||||
static WORLDS: Lazy<Mutex<HashMap<WorldId, PhysicsWorld>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
static NEXT_WORLD_ID: Lazy<Mutex<WorldId>> = Lazy::new(|| Mutex::new(1));
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pinball_create_world(gx: f32, gy: f32) -> WorldId {
|
||||
let mut next = NEXT_WORLD_ID.lock().unwrap();
|
||||
let id = *next;
|
||||
*next = next.wrapping_add(1);
|
||||
|
||||
let world = PhysicsWorld::new(gx, gy);
|
||||
WORLDS.lock().unwrap().insert(id, world);
|
||||
id
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pinball_step_world(world_id: WorldId) {
|
||||
if let Some(world) = WORLDS.lock().unwrap().get_mut(&world_id) {
|
||||
world.step();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pinball_create_dynamic_body(world_id: WorldId, x: f32, y: f32) -> u32 {
|
||||
let mut map = WORLDS.lock().unwrap();
|
||||
if let Some(world) = map.get_mut(&world_id) {
|
||||
world.create_dynamic_body(x, y)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pinball_get_body_x(world_id: WorldId, body_id: u32) -> f32 {
|
||||
let map = WORLDS.lock().unwrap();
|
||||
if let Some(world) = map.get(&world_id) {
|
||||
if let Some((x, _)) = world.get_body_position(body_id) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
0.0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pinball_get_body_y(world_id: WorldId, body_id: u32) -> f32 {
|
||||
let map = WORLDS.lock().unwrap();
|
||||
if let Some(world) = map.get(&world_id) {
|
||||
if let Some((_, y)) = world.get_body_position(body_id) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
0.0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user