use std::{f32::consts::PI, fmt};
use specs::{Component, DenseVecStorage, FlaggedStorage};
use crate::{
nalgebra::{Isometry3, RealField, Vector3},
ncollide::{
shape::{Ball, Cuboid, ShapeHandle},
world::CollisionGroups,
},
nphysics::{
material::{BasicMaterial, MaterialHandle},
object::ColliderHandle,
},
};
#[derive(Clone, Copy, Debug)]
pub enum Shape<N: RealField> {
Circle(N),
Rectangle(N, N, N),
}
impl<N: RealField> Shape<N> {
fn handle(&self, margin: N) -> ShapeHandle<N> {
match *self {
Shape::Circle(radius) => ShapeHandle::new(Ball::new(radius)),
Shape::Rectangle(width, height, depth) => ShapeHandle::new(Cuboid::new(Vector3::new(
width / N::from_f32(2.0).unwrap() - margin,
height / N::from_f32(2.0).unwrap() - margin,
depth / N::from_f32(2.0).unwrap() - margin,
))),
}
}
}
#[derive(Clone)]
pub struct PhysicsCollider<N: RealField> {
pub(crate) handle: Option<ColliderHandle>,
pub shape: Shape<N>,
pub offset_from_parent: Isometry3<N>,
pub density: N,
pub material: MaterialHandle<N>,
pub margin: N,
pub collision_groups: CollisionGroups,
pub linear_prediction: N,
pub angular_prediction: N,
pub sensor: bool,
}
impl<N: RealField> Component for PhysicsCollider<N> {
type Storage = FlaggedStorage<Self, DenseVecStorage<Self>>;
}
impl<N: RealField> fmt::Debug for PhysicsCollider<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"PhysicsCollider {{ \
handle: {:?}, \
offset_from_parent: {:?}, \
density: {}, \
margin: {}, \
collision_group: {:?}, \
linear_prediction: {}, \
angular_prediction: {}, \
sensor: {} \
}}",
self.handle,
self.offset_from_parent,
self.density,
self.margin,
self.collision_groups,
self.linear_prediction,
self.angular_prediction,
self.sensor,
)?;
Ok(())
}
}
impl<N: RealField> PhysicsCollider<N> {
pub(crate) fn shape_handle(&self) -> ShapeHandle<N> {
self.shape.handle(self.margin)
}
}
pub struct PhysicsColliderBuilder<N: RealField> {
shape: Shape<N>,
offset_from_parent: Isometry3<N>,
density: N,
material: MaterialHandle<N>,
margin: N,
collision_groups: CollisionGroups,
linear_prediction: N,
angular_prediction: N,
sensor: bool,
}
impl<N: RealField> From<Shape<N>> for PhysicsColliderBuilder<N> {
fn from(shape: Shape<N>) -> Self {
Self {
shape,
offset_from_parent: Isometry3::identity(),
density: N::from_f32(1.3).unwrap(),
material: MaterialHandle::new(BasicMaterial::default()),
margin: N::from_f32(0.2).unwrap(), collision_groups: CollisionGroups::default(),
linear_prediction: N::from_f32(0.002).unwrap(),
angular_prediction: N::from_f32(PI / 180.0 * 5.0).unwrap(),
sensor: false,
}
}
}
impl<N: RealField> PhysicsColliderBuilder<N> {
pub fn offset_from_parent(mut self, offset_from_parent: Isometry3<N>) -> Self {
self.offset_from_parent = offset_from_parent;
self
}
pub fn density(mut self, density: N) -> Self {
self.density = density;
self
}
pub fn material(mut self, material: MaterialHandle<N>) -> Self {
self.material = material;
self
}
pub fn margin(mut self, margin: N) -> Self {
self.margin = margin;
self
}
pub fn collision_groups(mut self, collision_groups: CollisionGroups) -> Self {
self.collision_groups = collision_groups;
self
}
pub fn linear_prediction(mut self, linear_prediction: N) -> Self {
self.linear_prediction = linear_prediction;
self
}
pub fn angular_prediction(mut self, angular_prediction: N) -> Self {
self.angular_prediction = angular_prediction;
self
}
pub fn sensor(mut self, sensor: bool) -> Self {
self.sensor = sensor;
self
}
pub fn build(self) -> PhysicsCollider<N> {
PhysicsCollider {
handle: None,
shape: self.shape,
offset_from_parent: self.offset_from_parent,
density: self.density,
material: self.material,
margin: self.margin,
collision_groups: self.collision_groups,
linear_prediction: self.linear_prediction,
angular_prediction: self.angular_prediction,
sensor: self.sensor,
}
}
}