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 }