pub mod debug_render; use fxhash::FxHashMap; use glam::Vec2; use rapier2d::{ dynamics::IntegrationParameters, geometry, glamx::vec2, pipeline::{DebugRenderPipeline, PhysicsWorld}, 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 world: PhysicsWorld, pub debug_render_pipeline: DebugRenderPipeline, } impl PhysicsManager { pub fn new() -> Self { let mut world = PhysicsWorld::new(); let gravity = vec2(0.0, 9.81); world.gravity = gravity; world.integration_parameters = IntegrationParameters { // 20 pixels <-> 1 meter length_unit: CELLS_TO_METRES, dt: PHYSICS_DELTA_TIME, ..prelude::IntegrationParameters::default() }; PhysicsManager { world, 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) { self.physics_manager.world.step(); } pub fn debug_render(&mut self, mode: DebugRenderMode) -> &[DebugVertex] { puffin::profile_function!(); self.debug_line_buffer.vertices.clear(); self.physics_manager.debug_render_pipeline.mode = mode; self.physics_manager.world.debug_render( &mut self.physics_manager.debug_render_pipeline, &mut self.debug_line_buffer, ); &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.world.remove_collider(handle); } let handle = self.physics_manager.world.insert_collider(collider, None); 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(), } } }