use super::{ComponentInspector, InspectorContext};
use crate::ecs::physics::components::{ColliderComponent, ColliderShape, RigidBodyComponent};
use crate::ecs::physics::types::{LockedAxes, RigidBodyType};
use crate::prelude::*;
pub struct PhysicsInspector;
impl ComponentInspector for PhysicsInspector {
fn name(&self) -> &str {
"Physics"
}
fn has_component(&self, world: &World, entity: Entity) -> bool {
world.entity_has_rigid_body(entity)
}
fn add_component(&self, world: &mut World, entity: Entity) {
world.add_components(
entity,
crate::ecs::world::RIGID_BODY | crate::ecs::world::COLLIDER,
);
world.set_rigid_body(entity, RigidBodyComponent::new_dynamic());
world.set_collider(entity, ColliderComponent::default());
}
fn remove_component(&self, world: &mut World, entity: Entity) {
world.remove_rigid_body(entity);
world.remove_collider(entity);
}
fn ui(
&mut self,
world: &mut World,
entity: Entity,
ui: &mut egui::Ui,
_context: &mut InspectorContext,
) {
rigid_body_ui(world, entity, ui);
ui.separator();
collider_ui(world, entity, ui);
}
}
fn rigid_body_ui(world: &mut World, entity: Entity, ui: &mut egui::Ui) {
if let Some(rigid_body) = world.get_rigid_body_mut(entity) {
ui.label(egui::RichText::new("Rigid Body").strong());
let type_label = match rigid_body.body_type {
RigidBodyType::Dynamic => "Dynamic",
RigidBodyType::Fixed => "Fixed",
RigidBodyType::KinematicPositionBased => "Kinematic (Position)",
RigidBodyType::KinematicVelocityBased => "Kinematic (Velocity)",
};
egui::ComboBox::from_id_salt("rb_type")
.selected_text(type_label)
.show_ui(ui, |ui| {
ui.selectable_value(&mut rigid_body.body_type, RigidBodyType::Dynamic, "Dynamic");
ui.selectable_value(&mut rigid_body.body_type, RigidBodyType::Fixed, "Fixed");
ui.selectable_value(
&mut rigid_body.body_type,
RigidBodyType::KinematicPositionBased,
"Kinematic (Position)",
);
ui.selectable_value(
&mut rigid_body.body_type,
RigidBodyType::KinematicVelocityBased,
"Kinematic (Velocity)",
);
});
if rigid_body.body_type == RigidBodyType::Dynamic {
ui.horizontal(|ui| {
ui.label("Mass:");
ui.add(
egui::DragValue::new(&mut rigid_body.mass)
.speed(0.1)
.range(0.001..=10000.0),
);
});
}
ui.separator();
ui.label(egui::RichText::new("Locked Axes").strong());
let mut translation_x = rigid_body
.locked_axes
.contains(LockedAxes::TRANSLATION_LOCKED_X);
let mut translation_y = rigid_body
.locked_axes
.contains(LockedAxes::TRANSLATION_LOCKED_Y);
let mut translation_z = rigid_body
.locked_axes
.contains(LockedAxes::TRANSLATION_LOCKED_Z);
let mut rotation_x = rigid_body
.locked_axes
.contains(LockedAxes::ROTATION_LOCKED_X);
let mut rotation_y = rigid_body
.locked_axes
.contains(LockedAxes::ROTATION_LOCKED_Y);
let mut rotation_z = rigid_body
.locked_axes
.contains(LockedAxes::ROTATION_LOCKED_Z);
ui.label("Translation:");
ui.horizontal(|ui| {
ui.checkbox(&mut translation_x, "X");
ui.checkbox(&mut translation_y, "Y");
ui.checkbox(&mut translation_z, "Z");
});
ui.label("Rotation:");
ui.horizontal(|ui| {
ui.checkbox(&mut rotation_x, "X");
ui.checkbox(&mut rotation_y, "Y");
ui.checkbox(&mut rotation_z, "Z");
});
let mut axes = LockedAxes::empty();
if translation_x {
axes |= LockedAxes::TRANSLATION_LOCKED_X;
}
if translation_y {
axes |= LockedAxes::TRANSLATION_LOCKED_Y;
}
if translation_z {
axes |= LockedAxes::TRANSLATION_LOCKED_Z;
}
if rotation_x {
axes |= LockedAxes::ROTATION_LOCKED_X;
}
if rotation_y {
axes |= LockedAxes::ROTATION_LOCKED_Y;
}
if rotation_z {
axes |= LockedAxes::ROTATION_LOCKED_Z;
}
rigid_body.locked_axes = axes;
}
}
fn collider_ui(world: &mut World, entity: Entity, ui: &mut egui::Ui) {
if let Some(collider) = world.get_collider_mut(entity) {
ui.label(egui::RichText::new("Collider").strong());
let shape_label = match &collider.shape {
ColliderShape::Ball { .. } => "Ball",
ColliderShape::Cuboid { .. } => "Cuboid",
ColliderShape::Capsule { .. } => "Capsule",
ColliderShape::Cylinder { .. } => "Cylinder",
ColliderShape::Cone { .. } => "Cone",
ColliderShape::TriMesh { .. } => "TriMesh",
ColliderShape::HeightField { .. } => "HeightField",
ColliderShape::ConvexMesh { .. } => "ConvexMesh",
};
ui.horizontal(|ui| {
ui.label("Shape:");
ui.label(shape_label);
});
match &mut collider.shape {
ColliderShape::Ball { radius } => {
ui.horizontal(|ui| {
ui.label("Radius:");
ui.add(
egui::DragValue::new(radius)
.speed(0.01)
.range(0.001..=100.0),
);
});
}
ColliderShape::Cuboid { hx, hy, hz } => {
ui.horizontal(|ui| {
ui.add(
egui::DragValue::new(hx)
.speed(0.01)
.range(0.001..=100.0)
.prefix("X: "),
);
ui.add(
egui::DragValue::new(hy)
.speed(0.01)
.range(0.001..=100.0)
.prefix("Y: "),
);
ui.add(
egui::DragValue::new(hz)
.speed(0.01)
.range(0.001..=100.0)
.prefix("Z: "),
);
});
}
ColliderShape::Capsule {
half_height,
radius,
} => {
ui.horizontal(|ui| {
ui.label("Half Height:");
ui.add(
egui::DragValue::new(half_height)
.speed(0.01)
.range(0.001..=100.0),
);
});
ui.horizontal(|ui| {
ui.label("Radius:");
ui.add(
egui::DragValue::new(radius)
.speed(0.01)
.range(0.001..=100.0),
);
});
}
ColliderShape::Cylinder {
half_height,
radius,
} => {
ui.horizontal(|ui| {
ui.label("Half Height:");
ui.add(
egui::DragValue::new(half_height)
.speed(0.01)
.range(0.001..=100.0),
);
});
ui.horizontal(|ui| {
ui.label("Radius:");
ui.add(
egui::DragValue::new(radius)
.speed(0.01)
.range(0.001..=100.0),
);
});
}
ColliderShape::Cone {
half_height,
radius,
} => {
ui.horizontal(|ui| {
ui.label("Half Height:");
ui.add(
egui::DragValue::new(half_height)
.speed(0.01)
.range(0.001..=100.0),
);
});
ui.horizontal(|ui| {
ui.label("Radius:");
ui.add(
egui::DragValue::new(radius)
.speed(0.01)
.range(0.001..=100.0),
);
});
}
_ => {
ui.label(
egui::RichText::new("Shape parameters not editable")
.small()
.weak(),
);
}
}
ui.separator();
ui.horizontal(|ui| {
ui.label("Friction:");
ui.add(egui::Slider::new(&mut collider.friction, 0.0..=2.0));
});
ui.horizontal(|ui| {
ui.label("Restitution:");
ui.add(egui::Slider::new(&mut collider.restitution, 0.0..=1.0));
});
ui.horizontal(|ui| {
ui.label("Sensor:");
ui.checkbox(&mut collider.is_sensor, "");
});
}
}