specs-physics

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

bodies.rs (7924B)


      1 use specs::{Component, DenseVecStorage, FlaggedStorage};
      2 
      3 use crate::{
      4     nalgebra::{Isometry3, Matrix3, Point3, RealField, Vector3},
      5     nphysics::{
      6         algebra::{Force3, ForceType, Velocity3},
      7         object::{Body, BodyPart, BodyStatus, DefaultBodyHandle, RigidBody, RigidBodyDesc},
      8     },
      9 };
     10 
     11 pub mod util {
     12     use specs::{Component, DenseVecStorage, FlaggedStorage};
     13 
     14     use crate::{
     15         bodies::Position,
     16         nalgebra::{Isometry3, RealField},
     17     };
     18 
     19     pub struct SimplePosition<N: RealField>(pub Isometry3<N>);
     20 
     21     impl<N: RealField> Position<N> for SimplePosition<N> {
     22         fn isometry(&self) -> &Isometry3<N> {
     23             &self.0
     24         }
     25 
     26         fn isometry_mut(&mut self) -> &mut Isometry3<N> {
     27             &mut self.0
     28         }
     29 
     30         fn set_isometry(&mut self, isometry: &Isometry3<N>) -> &mut Self {
     31             self.0.rotation = isometry.rotation;
     32             self.0.translation = isometry.translation;
     33             self
     34         }
     35     }
     36 
     37     impl<N: RealField> Component for SimplePosition<N> {
     38         type Storage = FlaggedStorage<Self, DenseVecStorage<Self>>;
     39     }
     40 }
     41 
     42 /// An implementation of the `Position` trait is required for the
     43 /// synchronisation of the position of Specs and nphysics objects.
     44 ///
     45 /// Initially, it is used to position bodies in the nphysics `World`. Then after
     46 /// progressing the `World` it is used to synchronise the updated positions back
     47 /// towards Specs.
     48 pub trait Position<N: RealField>:
     49     Component<Storage = FlaggedStorage<Self, DenseVecStorage<Self>>> + Send + Sync
     50 {
     51     fn isometry(&self) -> &Isometry3<N>;
     52     fn isometry_mut(&mut self) -> &mut Isometry3<N>;
     53     fn set_isometry(&mut self, isometry: &Isometry3<N>) -> &mut Self;
     54 }
     55 
     56 
     57 /// The `PhysicsBody` `Component` represents a `PhysicsWorld` `RigidBody` in
     58 /// Specs and contains all the data required for the synchronisation between
     59 /// both worlds.
     60 #[derive(Clone, Copy, Debug)]
     61 pub struct PhysicsBody<N: RealField> {
     62     pub(crate) handle: Option<DefaultBodyHandle>,
     63     pub gravity_enabled: bool,
     64     pub body_status: BodyStatus,
     65     pub velocity: Velocity3<N>,
     66     pub angular_inertia: Matrix3<N>,
     67     pub mass: N,
     68     pub local_center_of_mass: Point3<N>,
     69     pub rotations_kinematic: Vector3<bool>,
     70     external_forces: Force3<N>,
     71 }
     72 
     73 impl<N: RealField> Component for PhysicsBody<N> {
     74     type Storage = FlaggedStorage<Self, DenseVecStorage<Self>>;
     75 }
     76 
     77 impl<N: RealField> PhysicsBody<N> {
     78     pub fn check_external_force(&self) -> &Force3<N> {
     79         &self.external_forces
     80     }
     81 
     82     pub fn apply_external_force(&mut self, force: &Force3<N>) -> &mut Self {
     83         self.external_forces += *force;
     84         self
     85     }
     86 
     87     /// For creating new rigid body from this component's values
     88     pub(crate) fn to_rigid_body_desc(&self) -> RigidBodyDesc<N> {
     89         RigidBodyDesc::new()
     90             .gravity_enabled(self.gravity_enabled)
     91             .status(self.body_status)
     92             .velocity(self.velocity)
     93             .angular_inertia(self.angular_inertia)
     94             .mass(self.mass)
     95             .local_center_of_mass(self.local_center_of_mass)
     96     }
     97 
     98     /// Note: applies forces by draining external force property
     99     pub(crate) fn apply_to_physics_world(&mut self, rigid_body: &mut RigidBody<N>) -> &mut Self {
    100         rigid_body.enable_gravity(self.gravity_enabled);
    101         rigid_body.set_status(self.body_status);
    102         rigid_body.set_velocity(self.velocity);
    103         rigid_body.set_angular_inertia(self.angular_inertia);
    104         rigid_body.set_mass(self.mass);
    105         rigid_body.set_local_center_of_mass(self.local_center_of_mass);
    106         rigid_body.apply_force(0, &self.drain_external_force(), ForceType::Force, true);
    107         rigid_body.set_rotations_kinematic(self.rotations_kinematic);
    108         self
    109     }
    110 
    111     pub(crate) fn update_from_physics_world(&mut self, rigid_body: &RigidBody<N>) -> &mut Self {
    112         // These two probably won't be modified but hey
    113         self.gravity_enabled = rigid_body.gravity_enabled();
    114         self.body_status = rigid_body.status();
    115 
    116         self.velocity = *rigid_body.velocity();
    117 
    118         let local_inertia = rigid_body.local_inertia();
    119         self.angular_inertia = local_inertia.angular;
    120         self.mass = local_inertia.linear;
    121         self
    122     }
    123 
    124     fn drain_external_force(&mut self) -> Force3<N> {
    125         let value = self.external_forces;
    126         self.external_forces = Force3::<N>::zero();
    127         value
    128     }
    129 }
    130 
    131 /// The `PhysicsBodyBuilder` implements the builder pattern for `PhysicsBody`s
    132 /// and is the recommended way of instantiating and customising new
    133 /// `PhysicsBody` instances.
    134 ///
    135 /// # Example
    136 ///
    137 /// ```rust
    138 /// use specs_physics::{
    139 ///     nalgebra::{Matrix3, Point3},
    140 ///     nphysics::{algebra::Velocity3, object::BodyStatus},
    141 ///     PhysicsBodyBuilder,
    142 /// };
    143 ///
    144 /// let physics_body = PhysicsBodyBuilder::from(BodyStatus::Dynamic)
    145 ///     .gravity_enabled(true)
    146 ///     .velocity(Velocity3::linear(1.0, 1.0, 1.0))
    147 ///     .angular_inertia(Matrix3::from_diagonal_element(3.0))
    148 ///     .mass(1.3)
    149 ///     .local_center_of_mass(Point3::new(0.0, 0.0, 0.0))
    150 ///     .build();
    151 /// ```
    152 pub struct PhysicsBodyBuilder<N: RealField> {
    153     gravity_enabled: bool,
    154     body_status: BodyStatus,
    155     velocity: Velocity3<N>,
    156     angular_inertia: Matrix3<N>,
    157     mass: N,
    158     local_center_of_mass: Point3<N>,
    159     rotations_kinematic: Vector3<bool>,
    160 }
    161 
    162 impl<N: RealField> From<BodyStatus> for PhysicsBodyBuilder<N> {
    163     /// Creates a new `PhysicsBodyBuilder` from the given `BodyStatus`. This
    164     /// also populates the `PhysicsBody` with sane defaults.
    165     fn from(body_status: BodyStatus) -> Self {
    166         Self {
    167             gravity_enabled: false,
    168             body_status,
    169             velocity: Velocity3::zero(),
    170             angular_inertia: Matrix3::zeros(),
    171             mass: N::from_f32(1.2).unwrap(),
    172             local_center_of_mass: Point3::origin(),
    173             rotations_kinematic: Vector3::new(false, false, false),
    174         }
    175     }
    176 }
    177 
    178 impl<N: RealField> PhysicsBodyBuilder<N> {
    179     /// Sets the `gravity_enabled` value of the `PhysicsBodyBuilder`.
    180     pub fn gravity_enabled(mut self, gravity_enabled: bool) -> Self {
    181         self.gravity_enabled = gravity_enabled;
    182         self
    183     }
    184 
    185     // Sets the `velocity` value of the `PhysicsBodyBuilder`.
    186     pub fn velocity(mut self, velocity: Velocity3<N>) -> Self {
    187         self.velocity = velocity;
    188         self
    189     }
    190 
    191     /// Sets the `angular_inertia` value of the `PhysicsBodyBuilder`.
    192     pub fn angular_inertia(mut self, angular_inertia: Matrix3<N>) -> Self {
    193         self.angular_inertia = angular_inertia;
    194         self
    195     }
    196 
    197     /// Sets the `mass` value of the `PhysicsBodyBuilder`.
    198     pub fn mass(mut self, mass: N) -> Self {
    199         self.mass = mass;
    200         self
    201     }
    202 
    203     /// Sets the `local_center_of_mass` value of the `PhysicsBodyBuilder`.
    204     pub fn local_center_of_mass(mut self, local_center_of_mass: Point3<N>) -> Self {
    205         self.local_center_of_mass = local_center_of_mass;
    206         self
    207     }
    208 
    209     pub fn rotations_kinematic(mut self, rotations_kinematic: Vector3<bool>) -> Self {
    210         self.rotations_kinematic = rotations_kinematic;
    211         self
    212     }
    213 
    214     pub fn lock_rotations(mut self, lock_rotations: bool) -> Self {
    215         self.rotations_kinematic = Vector3::new(lock_rotations, lock_rotations, lock_rotations);
    216         self
    217     }
    218 
    219     /// Builds the `PhysicsBody` from the values set in the `PhysicsBodyBuilder`
    220     /// instance.
    221     pub fn build(self) -> PhysicsBody<N> {
    222         PhysicsBody {
    223             handle: None,
    224             gravity_enabled: self.gravity_enabled,
    225             body_status: self.body_status,
    226             velocity: self.velocity,
    227             angular_inertia: self.angular_inertia,
    228             mass: self.mass,
    229             local_center_of_mass: self.local_center_of_mass,
    230             external_forces: Force3::zero(),
    231             rotations_kinematic: self.rotations_kinematic,
    232         }
    233     }
    234 }