specs-physics

Build Status Crates.io MIT/Apache Docs.rs

specs-physics aims to be an easily usable and extendable nphysics physics engine integration for applications and games that utilise the Specs ECS.

The dream is to simply create Entitys with a set of configurable Components and have most of your physics covered, be it collision/proximity detection, velocity and acceleration or gravity.

Usage

To use specs-physics, add the following dependency to your projects Cargo.toml:

toml [dependencies] specs-physics = "0.2.0"

specs-physics defines a set of Specs Systems and Components to handle the creation, modification and removal of nphysics objects (RigidBody, Collider) and the synchronisation of object positions and global gravity between both worlds.

Generic types

All Systems and Components provided by this crate require between one and two type parameters to function properly. These were explicitly introduced to keep this integration as generic as possible and allow compatibility with as many external crates and game engines as possible.

N: RealField - nphysics is built upon nalgebra and uses various types and structures from this crate. specs-physics builds up on this even further and utilises the same structures, which all work with any type that implements nalgebra::RealField. nalgebra::RealField is by default implemented for various standard types, such as f32 andf64. nalgebra is re-exported under specs_physics::math.

P: Component<Storage = FlaggedStorage<P, DenseVecStorage<P>>> + Position<N> + Send + Sync - a more complex type parameter which looks a bit intimidating at first but ultimately just requires a Component, that also implements the specs_physics::bodies::Position trait and uses a FlaggedStorage. This Position Component is used to initially place a RigidBody in the nphysics world and later used to synchronise the updated positions of these bodies back into the Specs world.

Example for a Position Component: ```rust use specs_physics::bodies::Position;

struct Pos { x: f32, y: f32, z: f32, }

impl Component for Pos { type Storage = FlaggedStorage>; }

impl Position for Pos { fn position(&self) -> (f32, f32, f32) { (self.x, self.y, self.z) }

fn set_position(&mut self, x: f32, y: f32, z: f32) {
    self.x = x;
    self.y = y;
    self.z = z;
}

} ```

Components

PhysicsBody

The specs_physics::PhysicsBody Component is used to define RigidBody from the comforts of your Specs world. Changes to the PhysicsBody will automatically be synchronised with nphysics.

Example:

```rust use specs_physics::{ bodies::BodyStatus, math::{Matrix3, Point3, Vector3}, PhysicsBodyBuilder, };

let physicsbody = PhysicsBodyBuilder::from(BodyStatus::Dynamic) .gravityenabled(true) .velocity(Vector3::new(1.0, 1.0, 1.0)) .angularinertia(Matrix3::fromdiagonalelement(3.0)) .mass(1.3) .localcenterofmass(Point3::new(0.0, 0.0, 0.0)) .build(); ```

PhysicsCollider

specs_physics::PhysicsColliders are the counterpart to PhysicsBodys. They can exist on their own or as a part of a PhysicsBody PhysicsColliders are used to define and create Colliders in nphysics.

Example:

```rust use specs_physics::{ colliders::{ material::{BasicMaterial, MaterialHandle}, CollisionGroups, }, math::Isometry3, PhysicsColliderBuilder, Shape, };

let physicscollider = PhysicsColliderBuilder::from(Shape::Rectangle(10.0, 10.0, 1.0)) .offsetfromparent(Isometry3::identity()) .density(1.2) .material(MaterialHandle::new(BasicMaterial::default())) .margin(0.02) .collisiongroups(CollisionGroups::default()) .linearprediction(0.001) .angularprediction(0.0) .sensor(true) .build(); ```

To assign multiple Colliders the the same body, Entity hierarchy can be used. This utilises specs-hierarchy.

Systems

The following Systems currently exist and should be added to your Dispatcher in order:

  1. specs_physics::systems::SyncBodiesToPhysicsSystem - handles the creation, modification and removal of RigidBodies based on the PhysicsBody Component and an implementation of the Position trait.
  2. specs_physics::systems::SyncCollidersToPhysicsSystem - handles the creation, modification and removal of Colliders based on the PhysicsCollider Component. This System depends on SyncBodiesToPhysicsSystem as Colliders can depend on RigidBodies.
  3. specs_physics::systems::SyncGravityToPhysicsSystem - handles the modification of the nphysics Worlds gravity.
  4. specs_physics::systems::PhysicsStepperSystem - handles the progression of the nphysics World and causes objects to actually move and change their position. This System is the backbone for collision detection.
  5. specs_physics::systems::SyncPositionsFromPhysicsSystem - handles the synchronisation of RigidBodies positions back into the Specs Components. This System also utilises the Position trait implementation.

An example Dispatcher with all required Systems:

rust let dispatcher = DispatcherBuilder::new() .with( SyncBodiesToPhysicsSystem::<f32, MyPosition>::default(), "sync_bodies_to_physics_system", &[], ) .with( SyncCollidersToPhysicsSystem::<f32, MyPosition>::default(), "sync_colliders_to_physics_system", &["sync_bodies_to_physics_system"], ) .with( SyncGravityToPhysicsSystem::<f32>::default(), "sync_gravity_to_physics_system", &[], ) .with( PhysicsStepperSystem::<f32>::default(), "physics_stepper_system", &[ "sync_bodies_to_physics_system", "sync_colliders_to_physics_system", "sync_gravity_to_physics_system", ], ) .with( SyncPositionsFromPhysicsSystem::<f32, MyPosition>::default(), "sync_positions_from_physics_system", &["physics_stepper_system"], ) .build();

Alternatively to building your own Dispatcher, you can always fall back on the convenience function specs_physics::dispatcher(), which returns a configured default Dispatcher for you.

Examples

Full examples can be found under src/examples. If anything is missing or unclear, feel free to open an issue or give me a poke!

Contributing

I'd appreciate any kind of contribution to this project, be it feature requests, bugs/issues, pull requests, documentation, tests or examples!

Please just try to format any code changes according to the rustfmt.toml rules. They're not exactly set in stone and I'm open for suggestions, but let's try to keep things tidy!

License

Distributed under the MIT License. See LICENSE for more information.

Acknowledgments

This project is heavily inspired by nphysics-ecs-dumb; they did most of the heavy lifting, I'm just building up on what they have started!

Special thanks to: - distransient - jojolepro