tirbofish/dropbear · diff
fix: physics-based bug fixes
Signature present but could not be verified.
Unverified
@@ -3,6 +3,75 @@ use crate::scripting::result::DropbearNativeResult; use crate::types::{NColour, NQuaternion, NVector3}; use dropbear_engine::graphics::SharedGraphicsContext; use glam::{Quat, Vec3}; +use dropbear_engine::debug::DebugDraw; +use crate::physics::collider::ColliderShape; + +/// Extension traits for [`DebugDraw`](dropbear_engine::debug::DebugDraw) +pub trait DebugDrawExt { + fn draw_collider(&mut self, shape: &ColliderShape, translation: glam::Vec3, scale: glam::Vec3, rotation: Quat, colour: [f32; 4]); +} + +impl DebugDrawExt for DebugDraw { + fn draw_collider(&mut self, shape: &ColliderShape, translation: glam::Vec3, scale: glam::Vec3, rotation: Quat, colour: [f32; 4]) { + match &shape { + ColliderShape::Box { half_extents } => { + let he = glam::Vec3::new( + half_extents.x as f32 * scale.x, + half_extents.y as f32 * scale.y, + half_extents.z as f32 * scale.z, + ); + self.draw_obb(translation, he, rotation, colour); + } + ColliderShape::Sphere { radius } => { + let r = radius * scale.x.max(scale.y).max(scale.z); + self.draw_sphere(translation, r, colour); + } + ColliderShape::Capsule { + half_height, + radius, + } => { + let axis = rotation * glam::Vec3::Y; + let top = translation + axis * (half_height * scale.y); + let bottom = translation - axis * (half_height * scale.y); + self.draw_capsule( + bottom, + top, + radius * scale.x.max(scale.z), + colour, + ); + } + ColliderShape::Cylinder { + half_height, + radius, + } => { + let axis = rotation * glam::Vec3::Y; + self.draw_cylinder( + translation, + half_height * scale.y, + radius * scale.x.max(scale.z), + axis, + colour, + ); + } + ColliderShape::Cone { + half_height, + radius, + } => { + let axis = rotation * glam::Vec3::Y; + let apex = translation + axis * (half_height * scale.y); + let height = 2.0 * half_height * scale.y; + let r = radius * scale.x.max(scale.z); + self.draw_cone( + apex, + -(rotation * glam::Vec3::Y), + (r / height).atan(), + height, + colour, + ); + } + } + } +} macro_rules! with_debug { ($graphics:expr, |$dd:ident| $body:expr) => { @@ -201,6 +201,10 @@ impl PhysicsState { } builder = builder.active_events(active_events); + if collider_component.is_sensor { + builder = builder.active_collision_types(ActiveCollisionTypes::all()); + } + builder = builder.translation(Vector::from_array(collider_component.translation)); let rotation = UnitQuaternion::from_euler_angles( @@ -392,7 +392,9 @@ fn move_character( *collider.position() }; - let filter = QueryFilter::default().exclude_rigid_body(*rigid_body_handle); + let filter = QueryFilter::default() + .exclude_rigid_body(*rigid_body_handle) + .exclude_sensors(); let query_pipeline = physics_state.broad_phase.as_query_pipeline( physics_state.narrow_phase.query_dispatcher(), &physics_state.bodies, @@ -5,7 +5,7 @@ pub mod scripting; use crate::camera::CameraComponent; use crate::component::{ComponentRegistry, SerializedComponent}; -use crate::hierarchy::{Children, Parent, SceneHierarchy}; +use crate::hierarchy::{Children, EntityTransformExt, Parent, SceneHierarchy}; use crate::physics::PhysicsState; use crate::physics::collider::ColliderGroup; use crate::physics::kcc::KCC; @@ -279,8 +279,6 @@ impl SceneConfig { let entity = world.spawn(builder.build()); - self.register_physics_for_entity(world, entity); - if let Some(previous) = label_to_entity.insert(label_for_map.clone(), entity) { log::warn!( "Duplicate entity label '{}' detected; previous entity {:?} will be overwritten in hierarchy mapping", @@ -293,6 +291,10 @@ impl SceneConfig { } self.rebuild_hierarchy(world, &label_to_entity); + + for &entity in label_to_entity.values() { + self.register_physics_for_entity(world, entity); + } self.ensure_default_light(world, graphics.clone(), progress_sender.as_ref()) .await?; @@ -304,6 +306,14 @@ impl SceneConfig { } fn register_physics_for_entity(&mut self, world: &mut hecs::World, entity: hecs::Entity) { + let entity_transform_copy: Option<EntityTransform> = world + .query_one::<&EntityTransform>(entity) + .get() + .ok() + .map(|t: &EntityTransform| *t); + + let world_transform = entity_transform_copy.map(|t: EntityTransform| t.propagate(world, entity)); + if let Ok((label, e_trans, rigid, col_group, kcc)) = world .query_one::<( &Label, @@ -316,7 +326,8 @@ impl SceneConfig { { if let Some(body) = rigid { body.entity = label.clone(); - self.physics_state.register_rigidbody(body, e_trans.sync()); + let transform = world_transform.unwrap_or_else(|| e_trans.sync()); + self.physics_state.register_rigidbody(body, transform); } if let Some(group) = col_group { @@ -17,7 +17,7 @@ use eucalyptus_core::billboard::BillboardComponent; use eucalyptus_core::component::KotlinComponentDecl; use eucalyptus_core::entity_status::EntityStatus; use eucalyptus_core::hierarchy::EntityTransformExt; -use eucalyptus_core::physics::collider::{ColliderGroup, ColliderShape}; +use eucalyptus_core::physics::collider::{ColliderGroup}; use eucalyptus_core::properties::CustomProperties; use eucalyptus_core::states::{Label, SCENES, WorldLoadingStatus}; use eucalyptus_core::transform::OnRails; @@ -36,6 +36,7 @@ use std::{ }; use winit::event::{MouseScrollDelta, TouchPhase}; use winit::{event::WindowEvent, event_loop::ActiveEventLoop, keyboard::KeyCode}; +use eucalyptus_core::debug::DebugDrawExt; impl Scene for Editor { fn load(&mut self, graphics: Arc<SharedGraphicsContext>) { @@ -1108,7 +1109,7 @@ impl Scene for Editor { if show_hitboxes { puffin::profile_scope!("collider debug draw"); if let Some(debug_draw) = graphics.debug_draw.lock().as_mut() { - let colour = [0.0, 1.0, 0.0, 1.0]; + let colour = [0.0, 1.0, 0.0, 1.0]; // green let to_draw: Vec<_> = { let mut q = self.world.query::<(Entity, &ColliderGroup)>(); q.iter().map(|(e, cg)| (e, cg.colliders.clone())).collect() @@ -1128,63 +1129,7 @@ impl Scene for Editor { let (scale, rotation, translation) = final_matrix.to_scale_rotation_translation(); - match &collider.shape { - ColliderShape::Box { half_extents } => { - let he = glam::Vec3::new( - half_extents.x as f32 * scale.x, - half_extents.y as f32 * scale.y, - half_extents.z as f32 * scale.z, - ); - debug_draw.draw_obb(translation, he, rotation, colour); - } - ColliderShape::Sphere { radius } => { - let r = radius * scale.x.max(scale.y).max(scale.z); - debug_draw.draw_sphere(translation, r, colour); - } - ColliderShape::Capsule { - half_height, - radius, - } => { - let axis = rotation * glam::Vec3::Y; - let top = translation + axis * (half_height * scale.y); - let bottom = translation - axis * (half_height * scale.y); - debug_draw.draw_capsule( - bottom, - top, - radius * scale.x.max(scale.z), - colour, - ); - } - ColliderShape::Cylinder { - half_height, - radius, - } => { - let axis = rotation * glam::Vec3::Y; - debug_draw.draw_cylinder( - translation, - half_height * scale.y, - radius * scale.x.max(scale.z), - axis, - colour, - ); - } - ColliderShape::Cone { - half_height, - radius, - } => { - let axis = rotation * glam::Vec3::Y; - let apex = translation + axis * (half_height * scale.y); - let height = 2.0 * half_height * scale.y; - let r = radius * scale.x.max(scale.z); - debug_draw.draw_cone( - apex, - -(rotation * glam::Vec3::Y), - (r / height).atan(), - height, - colour, - ); - } - } + debug_draw.draw_collider(&collider.shape, translation, scale, rotation, colour); } } } @@ -137,7 +137,9 @@ impl Scene for PlayMode { 1.0 }; - let filter = QueryFilter::default().exclude_rigid_body(rigid_body_handle); + let filter = QueryFilter::default() + .exclude_rigid_body(rigid_body_handle) + .exclude_sensors(); let dispatcher = self.physics_state.narrow_phase.query_dispatcher(); let broad_phase = &mut self.physics_state.broad_phase; @@ -77,4 +77,23 @@ object Logger { } } -internal expect fun getCallerInfo(): String +internal expect fun getCallerInfo(): String + +/** + * Extension function to log and return a value if the value is null. + * + * # Example + * ``` + * val room1Sensor = engine + * .getEntity("room1_sensor") + * ?.getComponent(ColliderGroup) + * ?.getColliders() + * .orLogAndReturn("room1_sensor missing") { return } // returns if the value is null + * ``` + */ +inline fun <T> T?.orLogAndReturn(msg: String, returnBlock: () -> Nothing): T { + return this ?: run { + Logger.warn(msg) + returnBlock() + } +}