Galactica/crates/system/src/phys/physwrapper.rs
2024-01-23 21:21:15 -08:00

135 lines
3.4 KiB
Rust

use crossbeam::channel::Receiver;
use rapier2d::{
dynamics::{
CCDSolver, GenericJoint, ImpulseJointSet, IntegrationParameters, IslandManager,
MultibodyJointSet, RigidBody, RigidBodyHandle, RigidBodySet,
},
geometry::{BroadPhase, Collider, ColliderHandle, ColliderSet, CollisionEvent, NarrowPhase},
na::vector,
pipeline::{ChannelEventCollector, PhysicsPipeline},
};
/// Wraps Rapier2d physics parameters
pub struct PhysWrapper {
ip: IntegrationParameters,
pp: PhysicsPipeline,
im: IslandManager,
bp: BroadPhase,
np: NarrowPhase,
mj: MultibodyJointSet,
ccd: CCDSolver,
rigid_body_set: RigidBodySet,
collider_set: ColliderSet,
joint_set: ImpulseJointSet,
collision_handler: ChannelEventCollector,
/// Collision event queue
/// this should be emptied after every frame.
pub collision_queue: Receiver<CollisionEvent>,
}
impl PhysWrapper {
/// Make a new physics wrapper
pub fn new() -> Self {
let (collision_send, collision_queue) = crossbeam::channel::unbounded();
let (contact_force_send, _) = crossbeam::channel::unbounded();
Self {
ip: IntegrationParameters::default(),
pp: PhysicsPipeline::new(),
im: IslandManager::new(),
bp: BroadPhase::new(),
np: NarrowPhase::new(),
mj: MultibodyJointSet::new(),
ccd: CCDSolver::new(),
collision_queue,
collision_handler: ChannelEventCollector::new(collision_send, contact_force_send),
rigid_body_set: RigidBodySet::new(),
collider_set: ColliderSet::new(),
joint_set: ImpulseJointSet::new(),
}
}
/// Step physics sim by `t` seconds
pub fn step(&mut self, t: f32) {
self.ip.dt = t;
self.pp.step(
&vector![0.0, 0.0],
&self.ip,
&mut self.im,
&mut self.bp,
&mut self.np,
&mut self.rigid_body_set,
&mut self.collider_set,
&mut self.joint_set,
&mut self.mj,
&mut self.ccd,
None,
&(),
&mut self.collision_handler,
);
}
/// Remove a rigid body and all its colliders from this physics wrapper
pub fn remove_rigid_body(&mut self, body: RigidBodyHandle) -> Option<RigidBody> {
return self.rigid_body_set.remove(
body,
&mut self.im,
&mut self.collider_set,
&mut self.joint_set,
&mut self.mj,
true,
);
}
}
impl PhysWrapper {
/// Get a rigidbody from this physics wrapper
pub fn get_rigid_body(&self, h: RigidBodyHandle) -> Option<&RigidBody> {
self.rigid_body_set.get(h)
}
/// Get a rigidbody from this physics wrapper, mutably
pub fn get_rigid_body_mut(&mut self, h: RigidBodyHandle) -> Option<&mut RigidBody> {
self.rigid_body_set.get_mut(h)
}
/// Get a collider from this physics wrapper
pub fn get_collider(&self, h: ColliderHandle) -> Option<&Collider> {
self.collider_set.get(h)
}
/// Get a collider from this physics wrapper, mutably
pub fn get_collider_mut(&mut self, h: ColliderHandle) -> Option<&mut Collider> {
self.collider_set.get_mut(h)
}
/// Add a rigid body
pub fn insert_rigid_body(&mut self, rb: RigidBody) -> RigidBodyHandle {
self.rigid_body_set.insert(rb)
}
/// Attach a collider to a rigid body
pub fn insert_collider(
&mut self,
collider: Collider,
parent_handle: RigidBodyHandle,
) -> ColliderHandle {
self.collider_set
.insert_with_parent(collider, parent_handle, &mut self.rigid_body_set)
}
/// Add an impulse joint between two bodies
pub fn add_joint(
&mut self,
body1: RigidBodyHandle,
body2: RigidBodyHandle,
joint: impl Into<GenericJoint>,
) {
self.joint_set.insert(body1, body2, joint, false);
}
}