pub mod debug_render; use fxhash::FxHashMap; use glam::Vec2; use rapier2d::{geometry, glamx::vec2, prelude}; use crate::{ config::{CELLS_TO_METRES, CHUNK_SIZE, PHYSICS_DELTA_TIME}, sim::{ cell_manager::chunk::Chunk, lib::marching_squares::{Marchable, marching_squares_vertex_trace}, rb_manager::debug_render::{DebugLineBuffer, DebugVertex}, }, }; pub use rapier2d::pipeline::DebugRenderMode; pub struct PhysicsManager { pub rigid_body_set: prelude::RigidBodySet, pub collider_set: prelude::ColliderSet, pub physics_pipeline: prelude::PhysicsPipeline, pub integration_parameters: prelude::IntegrationParameters, pub island_manager: prelude::IslandManager, pub broad_phase: prelude::DefaultBroadPhase, pub narrow_phase: prelude::NarrowPhase, pub impulse_joint_set: prelude::ImpulseJointSet, pub multibody_joint_set: prelude::MultibodyJointSet, pub ccd_solver: prelude::CCDSolver, pub debug_render_pipeline: prelude::DebugRenderPipeline, } impl PhysicsManager { pub fn new() -> Self { PhysicsManager { rigid_body_set: prelude::RigidBodySet::new(), collider_set: prelude::ColliderSet::new(), physics_pipeline: prelude::PhysicsPipeline::new(), integration_parameters: prelude::IntegrationParameters { // 20 pixels <-> 1 meter length_unit: CELLS_TO_METRES, dt: PHYSICS_DELTA_TIME, ..prelude::IntegrationParameters::default() }, island_manager: prelude::IslandManager::new(), broad_phase: prelude::DefaultBroadPhase::new(), narrow_phase: prelude::NarrowPhase::new(), impulse_joint_set: prelude::ImpulseJointSet::new(), multibody_joint_set: prelude::MultibodyJointSet::new(), ccd_solver: prelude::CCDSolver::new(), debug_render_pipeline: prelude::DebugRenderPipeline::new( prelude::DebugRenderStyle { sleep_color_multiplier: [1.0; 4], sleep_eligible_color_multiplier: [1.0; 4], ..prelude::DebugRenderStyle::default() }, prelude::DebugRenderMode::default(), ), } } } // TODO remove pub struct RbManager { // move to sim manager chunk_colliders: FxHashMap<(i32, i32), geometry::ColliderHandle>, // move to sim manager pub physics_manager: PhysicsManager, debug_line_buffer: DebugLineBuffer, } impl RbManager { pub fn tick(&mut self, _delta_time: f32) { let gravity = vec2(0.0, 9.81); self.physics_manager.physics_pipeline.step( gravity, &self.physics_manager.integration_parameters, &mut self.physics_manager.island_manager, &mut self.physics_manager.broad_phase, &mut self.physics_manager.narrow_phase, &mut self.physics_manager.rigid_body_set, &mut self.physics_manager.collider_set, &mut self.physics_manager.impulse_joint_set, &mut self.physics_manager.multibody_joint_set, &mut self.physics_manager.ccd_solver, &(), &(), ); } pub fn debug_render(&mut self, mode: DebugRenderMode) -> &[DebugVertex] { puffin::profile_function!(); let physics = &mut self.physics_manager; self.debug_line_buffer.vertices.clear(); physics.debug_render_pipeline.mode = mode; physics.debug_render_pipeline.render( &mut self.debug_line_buffer, &physics.rigid_body_set, &physics.collider_set, &physics.impulse_joint_set, &physics.multibody_joint_set, &physics.narrow_phase, ); &self.debug_line_buffer.vertices } fn polyline_from_marchable( marchable: &impl Marchable, minimum_verts: Option, ) -> (Vec, Vec<[u32; 2]>) { let polys = marching_squares_vertex_trace(marchable); let mut vertices = Vec::new(); let mut indices = Vec::new(); let minimum_verts = minimum_verts.unwrap_or(3); for poly in polys { let v = vertices.len() as u32; let p = poly.len() as u32; if p < minimum_verts { continue; } for i in 0..p { vertices.push( (poly[i as usize] - (marchable.size().as_vec2() - 1.0) / 2.0) / CELLS_TO_METRES, ); indices.push([v + i, v + (i + 1) % p]); } } (vertices, indices) } fn polyline_collider_from_marchable( marchable: &impl Marchable, minimum_verts: Option, ) -> geometry::ColliderBuilder { let (vertices, indices) = RbManager::polyline_from_marchable(marchable, minimum_verts); geometry::ColliderBuilder::polyline(vertices, Some(indices)) } pub fn convex_hull_collider_from_marchable( marchable: &impl Marchable, minimum_verts: Option, ) -> geometry::ColliderBuilder { let (vertices, indices) = RbManager::polyline_from_marchable(marchable, minimum_verts); geometry::ColliderBuilder::convex_decomposition(&vertices, &indices) } pub fn upsert_chunk_collider(&mut self, cx: i32, cy: i32, chunk: &Chunk) { puffin::profile_function!(); let collider = RbManager::polyline_collider_from_marchable(chunk, Some(20)).translation( vec2( (cx as f32 + 0.5) * CHUNK_SIZE as f32, (cy as f32 + 0.5) * CHUNK_SIZE as f32, ) / CELLS_TO_METRES, ); if let Some(handle) = self.chunk_colliders.remove(&(cx, cy)) { self.physics_manager.collider_set.remove( handle, &mut self.physics_manager.island_manager, &mut self.physics_manager.rigid_body_set, false, ); } let handle = self.physics_manager.collider_set.insert(collider); self.chunk_colliders.insert((cx, cy), handle); } pub fn new() -> Self { RbManager { chunk_colliders: FxHashMap::default(), physics_manager: PhysicsManager::new(), debug_line_buffer: DebugLineBuffer::default(), } } }