use super::events::{CollisionEvent, CollisionEventCollector, ContactForceEvent};
use crate::ecs::lines::components::Line;
use freecs::Entity;
use rapier3d::prelude::*;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum JointType {
Fixed,
Revolute,
Prismatic,
Spherical,
Rope,
Spring,
}
pub struct JointInfo {
pub parent_entity: Entity,
pub child_entity: Entity,
pub joint_type: JointType,
pub collisions_enabled: bool,
pub spring_rest_length: Option<f32>,
pub spring_stiffness: Option<f32>,
pub spring_damping: Option<f32>,
}
pub struct PendingJoint {
pub parent_entity: Entity,
pub child_entity: Entity,
pub joint: GenericJoint,
pub joint_type: JointType,
pub collisions_enabled: bool,
pub spring_rest_length: Option<f32>,
pub spring_stiffness: Option<f32>,
pub spring_damping: Option<f32>,
}
pub struct PhysicsWorld {
pub gravity: Vector<Real>,
pub integration_parameters: IntegrationParameters,
pub physics_pipeline: PhysicsPipeline,
pub island_manager: IslandManager,
pub broad_phase: BroadPhaseBvh,
pub narrow_phase: NarrowPhase,
pub impulse_joint_set: ImpulseJointSet,
pub multibody_joint_set: MultibodyJointSet,
pub ccd_solver: CCDSolver,
pub(crate) physics_hooks: (),
pub(crate) event_collector: CollisionEventCollector,
collision_events: Vec<CollisionEvent>,
contact_force_events: Vec<ContactForceEvent>,
pub rigid_body_set: RigidBodySet,
pub collider_set: ColliderSet,
pub fixed_timestep: f32,
pub accumulator: f32,
pub max_substeps: u32,
pub interpolation_alpha: f32,
pub debug_draw: bool,
pub debug_entity: Option<freecs::Entity>,
pub debug_version: u64,
pub debug_static_lines_cache: HashMap<ColliderHandle, Vec<Line>>,
pub debug_last_version: u64,
pub pending_joints: Vec<PendingJoint>,
pub joint_registry: HashMap<ImpulseJointHandle, JointInfo>,
pub handle_to_entity: HashMap<RigidBodyHandle, Entity>,
pub entity_to_handle: HashMap<Entity, RigidBodyHandle>,
pub paused: bool,
pub grab: super::grab::GrabState,
}
impl Default for PhysicsWorld {
fn default() -> Self {
Self::new()
}
}
impl PhysicsWorld {
pub fn new() -> Self {
let integration_parameters = IntegrationParameters {
dt: 1.0 / 60.0,
..Default::default()
};
Self {
gravity: vector![0.0, -9.81, 0.0],
integration_parameters,
physics_pipeline: PhysicsPipeline::new(),
island_manager: IslandManager::new(),
broad_phase: BroadPhaseBvh::new(),
narrow_phase: NarrowPhase::new(),
impulse_joint_set: ImpulseJointSet::new(),
multibody_joint_set: MultibodyJointSet::new(),
ccd_solver: CCDSolver::new(),
physics_hooks: (),
event_collector: CollisionEventCollector::new(),
collision_events: Vec::new(),
contact_force_events: Vec::new(),
rigid_body_set: RigidBodySet::new(),
collider_set: ColliderSet::new(),
fixed_timestep: 1.0 / 60.0,
accumulator: 0.0,
max_substeps: 4,
interpolation_alpha: 0.0,
debug_draw: false,
debug_entity: None,
debug_version: 0,
debug_static_lines_cache: HashMap::new(),
debug_last_version: u64::MAX,
pending_joints: Vec::new(),
joint_registry: HashMap::new(),
handle_to_entity: HashMap::new(),
entity_to_handle: HashMap::new(),
paused: false,
grab: super::grab::GrabState::default(),
}
}
pub fn step(&mut self) {
let _span =
tracing::info_span!("physics_step", colliders = self.collider_set.len()).entered();
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,
&self.physics_hooks,
&self.event_collector,
);
}
pub fn collision_events(&self) -> &[CollisionEvent] {
&self.collision_events
}
pub fn contact_force_events(&self) -> &[ContactForceEvent] {
&self.contact_force_events
}
pub(crate) fn set_collision_events(&mut self, events: Vec<CollisionEvent>) {
self.collision_events = events;
}
pub(crate) fn set_contact_force_events(&mut self, events: Vec<ContactForceEvent>) {
self.contact_force_events = events;
}
pub(crate) fn clear_events(&mut self) {
self.collision_events.clear();
self.contact_force_events.clear();
}
pub fn query_pipeline(&self) -> QueryPipeline<'_> {
self.broad_phase.as_query_pipeline(
self.narrow_phase.query_dispatcher(),
&self.rigid_body_set,
&self.collider_set,
QueryFilter::default(),
)
}
pub fn get_interpolation_alpha(&self) -> f32 {
self.interpolation_alpha
}
pub fn add_rigid_body(&mut self, rigid_body: RigidBody) -> RigidBodyHandle {
self.rigid_body_set.insert(rigid_body)
}
pub fn add_collider(
&mut self,
collider: Collider,
parent_handle: RigidBodyHandle,
) -> ColliderHandle {
self.debug_version = self.debug_version.wrapping_add(1);
self.collider_set
.insert_with_parent(collider, parent_handle, &mut self.rigid_body_set)
}
pub fn remove_rigid_body(&mut self, handle: RigidBodyHandle) {
self.debug_version = self.debug_version.wrapping_add(1);
if let Some(entity) = self.handle_to_entity.remove(&handle) {
self.entity_to_handle.remove(&entity);
}
self.rigid_body_set.remove(
handle,
&mut self.island_manager,
&mut self.collider_set,
&mut self.impulse_joint_set,
&mut self.multibody_joint_set,
true,
);
}
pub fn get_rigid_body(&self, handle: RigidBodyHandle) -> Option<&RigidBody> {
self.rigid_body_set.get(handle)
}
pub fn get_rigid_body_mut(&mut self, handle: RigidBodyHandle) -> Option<&mut RigidBody> {
self.rigid_body_set.get_mut(handle)
}
pub fn add_joint(
&mut self,
body1: RigidBodyHandle,
body2: RigidBodyHandle,
joint: impl Into<GenericJoint>,
) -> ImpulseJointHandle {
self.impulse_joint_set.insert(body1, body2, joint, true)
}
}