specs-physics

[Fork] Integration of Amethyst, SPECS and Nphysics together.
git clone https://git.jojolepro.com/specs-physics.git
Log | Files | Refs | README | LICENSE

commit d07cb1ab98d7fa59a16ab8842bf273f7ad2586ca
parent 750547eaa9bec4e367975fd0d8c84771ac01170a
Author: Kel <kel@unclear.info>
Date:   Tue,  9 Jul 2019 12:35:37 -0400

Support all nphysics shapes (#8)

* Add support for all shapes

* That fork was a mistake

* Fix documentation

Diffstat:
MCargo.toml | 3++-
Mexamples/basic.rs | 14++++++++------
Mexamples/collision.rs | 21++++++++++++++-------
Mexamples/events.rs | 21++++++++++++++-------
Mexamples/hierarchy.rs | 23+++++++++++++----------
Mexamples/positions.rs | 14++++++++------
Msrc/colliders.rs | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Msrc/lib.rs | 20++++++--------------
Msrc/systems/mod.rs | 9++-------
Msrc/systems/physics_stepper.rs | 10+---------
Msrc/systems/sync_bodies_to_physics.rs | 21++++-----------------
Msrc/systems/sync_colliders_to_physics.rs | 25++++++-------------------
Msrc/systems/sync_parameters_to_physics.rs | 5+----
13 files changed, 181 insertions(+), 124 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -24,9 +24,10 @@ specs = "0.14.3" specs-hierarchy = "0.3.1" shrev = "1.1.1" nalgebra = "0.18.0" -ncollide3d = "0.19.1" +ncollide3d = "0.19" nphysics3d = "0.11.1" amethyst_core = { version = "0.6.0", optional = true } +objekt = "0.1.2" [dev-dependencies] simple_logger = "1.2.0" diff --git a/examples/basic.rs b/examples/basic.rs @@ -4,12 +4,9 @@ extern crate simple_logger; use specs::world::{Builder, World}; use specs_physics::{ colliders::Shape, - nalgebra::Isometry3, + nalgebra::{Isometry3, Vector3}, nphysics::object::BodyStatus, - physics_dispatcher, - PhysicsBodyBuilder, - PhysicsColliderBuilder, - SimplePosition, + physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, SimplePosition, }; fn main() { @@ -31,7 +28,12 @@ fn main() { 1.0, 1.0, 1.0, ))) .with(PhysicsBodyBuilder::<f32>::from(BodyStatus::Dynamic).build()) - .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(1.0, 1.0, 1.0)).build()) + .with( + PhysicsColliderBuilder::<f32>::from(Shape::Cuboid { + half_extents: Vector3::new(1.0, 1.0, 1.0), + }) + .build(), + ) .build(); // execute the dispatcher diff --git a/examples/collision.rs b/examples/collision.rs @@ -5,12 +5,9 @@ extern crate simple_logger; use specs::world::{Builder, World}; use specs_physics::{ colliders::Shape, - nalgebra::Isometry3, + nalgebra::{Isometry3, Vector3}, nphysics::{algebra::Velocity3, object::BodyStatus}, - physics_dispatcher, - PhysicsBodyBuilder, - PhysicsColliderBuilder, - SimplePosition, + physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, SimplePosition, }; fn main() { @@ -36,7 +33,12 @@ fn main() { .velocity(Velocity3::linear(1.0, 0.0, 0.0)) .build(), ) - .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(2.0, 2.0, 1.0)).build()) + .with( + PhysicsColliderBuilder::<f32>::from(Shape::Cuboid { + half_extents: Vector3::new(2.0, 2.0, 1.0), + }) + .build(), + ) .build(); // create an Entity with a static PhysicsBody component right next to the first @@ -47,7 +49,12 @@ fn main() { 3.0, 1.0, 1.0, ))) .with(PhysicsBodyBuilder::<f32>::from(BodyStatus::Static).build()) - .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(2.0, 2.0, 1.0)).build()) + .with( + PhysicsColliderBuilder::<f32>::from(Shape::Cuboid { + half_extents: Vector3::new(2.0, 2.0, 1.0), + }) + .build(), + ) .build(); // execute the dispatcher diff --git a/examples/events.rs b/examples/events.rs @@ -6,12 +6,9 @@ use specs::world::{Builder, World}; use specs_physics::{ colliders::Shape, events::ContactEvents, - nalgebra::Isometry3, + nalgebra::{Isometry3, Vector3}, nphysics::{algebra::Velocity3, object::BodyStatus}, - physics_dispatcher, - PhysicsBodyBuilder, - PhysicsColliderBuilder, - SimplePosition, + physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, SimplePosition, }; fn main() { @@ -38,7 +35,12 @@ fn main() { .velocity(Velocity3::linear(1.0, 0.0, 0.0)) .build(), ) - .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(2.0, 2.0, 1.0)).build()) + .with( + PhysicsColliderBuilder::<f32>::from(Shape::Cuboid { + half_extents: Vector3::new(2.0, 2.0, 1.0), + }) + .build(), + ) .build(); // create an Entity with a static PhysicsBody component right now to the first @@ -49,7 +51,12 @@ fn main() { 3.0, 1.0, 1.0, ))) .with(PhysicsBodyBuilder::<f32>::from(BodyStatus::Static).build()) - .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(2.0, 2.0, 1.0)).build()) + .with( + PhysicsColliderBuilder::<f32>::from(Shape::Cuboid { + half_extents: Vector3::new(2.0, 2.0, 1.0), + }) + .build(), + ) .build(); // execute the dispatcher diff --git a/examples/hierarchy.rs b/examples/hierarchy.rs @@ -4,13 +4,9 @@ extern crate simple_logger; use specs::world::{Builder, World}; use specs_physics::{ colliders::Shape, - nalgebra::Isometry3, + nalgebra::{Isometry3, Vector3}, nphysics::object::BodyStatus, - physics_dispatcher, - PhysicsBodyBuilder, - PhysicsColliderBuilder, - PhysicsParent, - SimplePosition, + physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, PhysicsParent, SimplePosition, }; fn main() { @@ -33,7 +29,12 @@ fn main() { 1.0, 1.0, 1.0, ))) .with(PhysicsBodyBuilder::<f32>::from(BodyStatus::Dynamic).build()) - .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(1.0, 1.0, 1.0)).build()) + .with( + PhysicsColliderBuilder::<f32>::from(Shape::Cuboid { + half_extents: Vector3::new(1.0, 1.0, 1.0), + }) + .build(), + ) .build(); // create the child Entity; if this Entity has its own PhysicsBody it'll more or @@ -46,9 +47,11 @@ fn main() { 1.0, 1.0, 1.0, ))) .with( - PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(1.0, 1.0, 1.0)) - .sensor(true) - .build(), + PhysicsColliderBuilder::<f32>::from(Shape::Cuboid { + half_extents: Vector3::new(1.0, 1.0, 1.0), + }) + .sensor(true) + .build(), ) .with(PhysicsParent { entity: parent }) .build(); diff --git a/examples/positions.rs b/examples/positions.rs @@ -5,12 +5,9 @@ extern crate simple_logger; use specs::world::{Builder, World}; use specs_physics::{ colliders::Shape, - nalgebra::Isometry3, + nalgebra::{Isometry3, Vector3}, nphysics::{algebra::Velocity3, object::BodyStatus}, - physics_dispatcher, - PhysicsBodyBuilder, - PhysicsColliderBuilder, - SimplePosition, + physics_dispatcher, PhysicsBodyBuilder, PhysicsColliderBuilder, SimplePosition, }; fn main() { @@ -37,7 +34,12 @@ fn main() { .velocity(Velocity3::linear(1.0, 0.0, 0.0)) .build(), ) - .with(PhysicsColliderBuilder::<f32>::from(Shape::Rectangle(1.0, 1.0, 1.0)).build()) + .with( + PhysicsColliderBuilder::<f32>::from(Shape::Cuboid { + half_extents: Vector3::new(1.0, 1.0, 1.0), + }) + .build(), + ) .build(); // execute the dispatcher diff --git a/src/colliders.rs b/src/colliders.rs @@ -1,11 +1,14 @@ -use std::{f32::consts::PI, fmt}; +use std::{f32::consts::PI, fmt, ops::Deref}; use specs::{Component, DenseVecStorage, FlaggedStorage}; use crate::{ - nalgebra::{Isometry3, RealField, Vector3}, + nalgebra::{DMatrix, Isometry3, Point2, Point3, RealField, Unit, Vector3}, ncollide::{ - shape::{Ball, Cuboid, ShapeHandle}, + shape::{ + Ball, Capsule, Compound, ConvexHull, Cuboid, HeightField, Plane, Polyline, Segment, + ShapeHandle, TriMesh, Triangle, + }, world::CollisionGroups, }, nphysics::{ @@ -14,27 +17,109 @@ use crate::{ }, }; +pub type MeshData<N> = (Vec<Point3<N>>, Vec<Point3<usize>>, Option<Vec<Point2<N>>>); + +pub trait IntoMesh: objekt::Clone + Send + Sync { + type N: RealField; + + fn points(&self) -> MeshData<Self::N>; +} + +impl<'clone, N: RealField> IntoMesh for Box<(dyn IntoMesh<N = N> + 'clone)> { + type N = N; + + fn points(&self) -> MeshData<Self::N> { + self.deref().points() + } +} + +impl<'clone, N: RealField> Clone for Box<dyn IntoMesh<N = N> + 'clone> { + fn clone(&self) -> Self { + objekt::clone_box(&*self) + } +} + /// `Shape` serves as an abstraction over nphysics `ShapeHandle`s and makes it /// easier to configure and define said `ShapeHandle`s for the user without /// having to know the underlying nphysics API. -#[derive(Clone, Copy, Debug)] +#[derive(Clone)] pub enum Shape<N: RealField> { - Circle(N), - Rectangle(N, N, N), + Ball { + radius: N, + }, + Capsule { + half_height: N, + radius: N, + }, + Compound { + parts: Vec<(Isometry3<N>, Shape<N>)>, + }, + ConvexHull { + points: Vec<Point3<N>>, + }, + Cuboid { + half_extents: Vector3<N>, + }, + HeightField { + heights: DMatrix<N>, + scale: Vector3<N>, + }, + Plane { + normal: Unit<Vector3<N>>, + }, + Polyline { + points: Vec<Point3<N>>, + indices: Option<Vec<Point2<usize>>>, + }, + Segment { + a: Point3<N>, + b: Point3<N>, + }, + TriMesh { + handle: Box<dyn IntoMesh<N = N>>, + }, + Triangle { + a: Point3<N>, + b: Point3<N>, + c: Point3<N>, + }, } impl<N: RealField> Shape<N> { /// Converts a `Shape` and its values into its corresponding `ShapeHandle` /// type. The `ShapeHandle` is used to define a `Collider` in the /// `PhysicsWorld`. - 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, - ))), + fn handle(&self) -> ShapeHandle<N> { + match self { + Shape::Ball { radius } => ShapeHandle::new(Ball::<N>::new(*radius)), + Shape::Capsule { + half_height, + radius, + } => ShapeHandle::new(Capsule::new(*half_height, *radius)), + Shape::Compound { parts } => ShapeHandle::new(Compound::new( + parts + .into_iter() + .map(|part| (part.0, part.1.handle())) + .collect(), + )), + Shape::ConvexHull { points } => ShapeHandle::new( + ConvexHull::try_from_points(&points) + .expect("Failed to generate Convex Hull from points."), + ), + Shape::Cuboid { half_extents } => ShapeHandle::new(Cuboid::new(*half_extents)), + Shape::HeightField { heights, scale } => { + ShapeHandle::new(HeightField::new(heights.clone(), *scale)) + } + Shape::Plane { normal } => ShapeHandle::new(Plane::new(*normal)), + Shape::Polyline { points, indices } => { + ShapeHandle::new(Polyline::new(points.clone(), indices.clone())) + } + Shape::Segment { a, b } => ShapeHandle::new(Segment::new(*a, *b)), + Shape::TriMesh { handle } => { + let data = handle.points(); + ShapeHandle::new(TriMesh::new(data.0, data.1, data.2)) + } + Shape::Triangle { a, b, c } => ShapeHandle::new(Triangle::new(*a, *b, *c)), } } } @@ -92,7 +177,7 @@ impl<N: RealField> PhysicsCollider<N> { /// Returns the `ShapeHandle` for `shape`, taking the `margin` into /// consideration. pub(crate) fn shape_handle(&self) -> ShapeHandle<N> { - self.shape.handle(self.margin) + self.shape.handle() } } @@ -105,13 +190,13 @@ impl<N: RealField> PhysicsCollider<N> { /// ```rust /// use specs_physics::{ /// colliders::Shape, -/// nalgebra::Isometry3, +/// nalgebra::{Isometry3, Vector3}, /// ncollide::world::CollisionGroups, /// nphysics::material::{BasicMaterial, MaterialHandle}, /// PhysicsColliderBuilder, /// }; /// -/// let physics_collider = PhysicsColliderBuilder::from(Shape::Rectangle(10.0, 10.0, 1.0)) +/// let physics_collider = PhysicsColliderBuilder::from(Shape::Cuboid{ half_extents: Vector3::new(10.0, 10.0, 1.0) }) /// .offset_from_parent(Isometry3::identity()) /// .density(1.2) /// .material(MaterialHandle::new(BasicMaterial::default())) diff --git a/src/lib.rs b/src/lib.rs @@ -113,13 +113,14 @@ //! ```rust //! use specs_physics::{ //! colliders::Shape, -//! nalgebra::Isometry3, +//! nalgebra::{Isometry3, Vector3}, //! ncollide::world::CollisionGroups, //! nphysics::material::{BasicMaterial, MaterialHandle}, //! PhysicsColliderBuilder, //! }; //! -//! let physics_collider = PhysicsColliderBuilder::from(Shape::Rectangle(10.0, 10.0, 1.0)) +//! let physics_collider = PhysicsColliderBuilder::from( +//! Shape::Cuboid{ half_extents: Vector3::new(10.0, 10.0, 1.0) }) //! .offset_from_parent(Isometry3::identity()) //! .density(1.2) //! .material(MaterialHandle::new(BasicMaterial::default())) @@ -246,13 +247,7 @@ pub use shrev; use std::collections::HashMap; use specs::{ - world::Index, - Component, - DenseVecStorage, - Dispatcher, - DispatcherBuilder, - Entity, - FlaggedStorage, + world::Index, Component, DenseVecStorage, Dispatcher, DispatcherBuilder, Entity, FlaggedStorage, }; use specs_hierarchy::Parent; @@ -272,11 +267,8 @@ use self::{ world::World, }, systems::{ - PhysicsStepperSystem, - SyncBodiesFromPhysicsSystem, - SyncBodiesToPhysicsSystem, - SyncCollidersToPhysicsSystem, - SyncParametersToPhysicsSystem, + PhysicsStepperSystem, SyncBodiesFromPhysicsSystem, SyncBodiesToPhysicsSystem, + SyncCollidersToPhysicsSystem, SyncParametersToPhysicsSystem, }, }; diff --git a/src/systems/mod.rs b/src/systems/mod.rs @@ -2,16 +2,11 @@ use std::ops::Deref; use specs::{ storage::{ComponentEvent, MaskedStorage}, - BitSet, - Component, - ReaderId, - Storage, - Tracked, + BitSet, Component, ReaderId, Storage, Tracked, }; pub use self::{ - physics_stepper::PhysicsStepperSystem, - sync_bodies_from_physics::SyncBodiesFromPhysicsSystem, + physics_stepper::PhysicsStepperSystem, sync_bodies_from_physics::SyncBodiesFromPhysicsSystem, sync_bodies_to_physics::SyncBodiesToPhysicsSystem, sync_colliders_to_physics::SyncCollidersToPhysicsSystem, sync_parameters_to_physics::SyncParametersToPhysicsSystem, diff --git a/src/systems/physics_stepper.rs b/src/systems/physics_stepper.rs @@ -1,15 +1,7 @@ use std::marker::PhantomData; use specs::{ - world::Index, - Entities, - Entity, - Read, - Resources, - System, - SystemData, - Write, - WriteExpect, + world::Index, Entities, Entity, Read, Resources, System, SystemData, Write, WriteExpect, }; use crate::{ diff --git a/src/systems/sync_bodies_to_physics.rs b/src/systems/sync_bodies_to_physics.rs @@ -1,17 +1,8 @@ use std::marker::PhantomData; use specs::{ - storage::ComponentEvent, - world::Index, - BitSet, - Join, - ReadStorage, - ReaderId, - Resources, - System, - SystemData, - WriteExpect, - WriteStorage, + storage::ComponentEvent, world::Index, BitSet, Join, ReadStorage, ReaderId, Resources, System, + SystemData, WriteExpect, WriteStorage, }; use crate::{ @@ -209,12 +200,8 @@ where #[cfg(test)] mod tests { use crate::{ - nalgebra::Isometry3, - nphysics::object::BodyStatus, - systems::SyncBodiesToPhysicsSystem, - Physics, - PhysicsBodyBuilder, - SimplePosition, + nalgebra::Isometry3, nphysics::object::BodyStatus, systems::SyncBodiesToPhysicsSystem, + Physics, PhysicsBodyBuilder, SimplePosition, }; use specs::{world::Builder, DispatcherBuilder, World}; diff --git a/src/systems/sync_colliders_to_physics.rs b/src/systems/sync_colliders_to_physics.rs @@ -1,16 +1,8 @@ use std::marker::PhantomData; use specs::{ - storage::ComponentEvent, - world::Index, - Join, - ReadStorage, - ReaderId, - Resources, - System, - SystemData, - WriteExpect, - WriteStorage, + storage::ComponentEvent, world::Index, Join, ReadStorage, ReaderId, Resources, System, + SystemData, WriteExpect, WriteStorage, }; use crate::{ @@ -18,8 +10,7 @@ use crate::{ colliders::PhysicsCollider, nalgebra::RealField, nphysics::object::{BodyPartHandle, ColliderDesc}, - Physics, - PhysicsParent, + Physics, PhysicsParent, }; use super::iterate_component_events; @@ -257,12 +248,8 @@ mod tests { use specs::{world::Builder, DispatcherBuilder, World}; use crate::{ - colliders::Shape, - nalgebra::Isometry3, - systems::SyncCollidersToPhysicsSystem, - Physics, - PhysicsColliderBuilder, - SimplePosition, + colliders::Shape, nalgebra::Isometry3, systems::SyncCollidersToPhysicsSystem, Physics, + PhysicsColliderBuilder, SimplePosition, }; #[test] @@ -284,7 +271,7 @@ mod tests { .with(SimplePosition::<f32>(Isometry3::<f32>::translation( 1.0, 1.0, 1.0, ))) - .with(PhysicsColliderBuilder::<f32>::from(Shape::Circle(5.0)).build()) + .with(PhysicsColliderBuilder::<f32>::from(Shape::Ball { radius: 5.0 }).build()) .build(); dispatcher.dispatch(&mut world.res); diff --git a/src/systems/sync_parameters_to_physics.rs b/src/systems/sync_parameters_to_physics.rs @@ -82,10 +82,7 @@ mod tests { use specs::{DispatcherBuilder, World}; use crate::{ - nalgebra::Vector3, - parameters::Gravity, - systems::SyncParametersToPhysicsSystem, - Physics, + nalgebra::Vector3, parameters::Gravity, systems::SyncParametersToPhysicsSystem, Physics, }; #[test]