1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
use crate::{Vec3, AABB};
/// A physical body in the Voxelize world.
#[derive(Default, Clone)]
pub struct RigidBody {
/// If `body.collision` is true that tick, means there's a collision detected.
pub collision: Option<[f32; 3]>,
/// If the body stepped upwards that tick.
pub stepped: bool,
/// The amount of drag this body has in air.
pub air_drag: f32,
/// The amount of drag this body has in fluid.
pub fluid_drag: f32,
/// A vector representing which axis is the body resting against something.
pub resting: Vec3<i32>,
/// Whether or not this body is in fluid.
pub in_fluid: bool,
/// Ratio of body this body is in fluid.
pub ratio_in_fluid: f32,
/// Velocity vector of the rigid body.
pub velocity: Vec3<f32>,
/// Forces vector of the rigid body.
pub forces: Vec3<f32>,
/// Impulses vector of the rigid body.
pub impulses: Vec3<f32>,
/// Counts how many frames this rigid body is static.
pub sleep_frame_count: i32,
/// AABB of this rigid body, describing its collision box.
pub aabb: AABB,
/// Mass of this rigid body.
pub mass: f32,
/// Friction of this rigid body.
pub friction: f32,
/// Restitution of this rigid body.
pub restitution: f32,
/// Gravity Multiplier of this rigid body. Set to 0 to fly.
pub gravity_multiplier: f32,
/// Whether or not this rigid body auto-steps up blocks.
pub auto_step: bool,
}
impl RigidBody {
/// Instantiate a new RigidBody using the Builder's pattern.
pub fn new(aabb: &AABB) -> RigidBodyBuilder {
RigidBodyBuilder::new(aabb)
}
/// Setter for rigid body's position, which is the center of the rigid body.
pub fn set_position(&mut self, px: f32, py: f32, pz: f32) {
let [offset_w, offset_h, offset_d] = self.aabb_offset();
self.aabb
.set_position(px - offset_w, py - offset_h, pz - offset_d);
self.mark_active()
}
/// Get the position of the rigid body, which is the center of the rigid body.
pub fn get_position(&self) -> Vec3<f32> {
let [offset_w, offset_h, offset_d] = self.aabb_offset();
Vec3(
self.aabb.min_x + offset_w,
self.aabb.min_y + offset_h,
self.aabb.min_z + offset_d,
)
}
/// Adds a vector to rigid body's internal force, which gets processed every tick.
pub fn apply_force(&mut self, fx: f32, fy: f32, fz: f32) {
self.forces[0] += fx;
self.forces[1] += fy;
self.forces[2] += fz;
self.mark_active();
}
/// Adds a vector to rigid body's internal impulse, which gets processed every tick.
pub fn apply_impulse(&mut self, ix: f32, iy: f32, iz: f32) {
self.impulses[0] += ix;
self.impulses[1] += iy;
self.impulses[2] += iz;
self.mark_active();
}
/// Get x-axis of the resting vector of a rigid body. A resting
/// vector indicates whether a body is resting or not.
pub fn at_rest_x(&self) -> i32 {
self.resting[0]
}
/// Get y-axis of the resting vector of a rigid body. A resting
/// vector indicates whether a body is resting or not.
pub fn at_rest_y(&self) -> i32 {
self.resting[1]
}
/// Get z-axis of the resting vector of a rigid body. A resting
/// vector indicates whether a body is resting or not.
pub fn at_rest_z(&self) -> i32 {
self.resting[2]
}
/// Mark rigid body as active in the physical world.
pub fn mark_active(&mut self) {
self.sleep_frame_count = 10;
}
/// Compute the offset from the minimum coordinates to the bottom center.
fn aabb_offset(&self) -> [f32; 3] {
[
self.aabb.width() / 2.0,
self.aabb.height() / 2.0,
self.aabb.depth() / 2.0,
]
}
}
/// Builder pattern for RigidBody.
#[derive(Default)]
pub struct RigidBodyBuilder {
aabb: AABB,
mass: f32,
friction: f32,
restitution: f32,
gravity_multiplier: f32,
auto_step: bool,
}
impl RigidBodyBuilder {
/// Create a new RigidBody with the builder pattern.
pub fn new(aabb: &AABB) -> Self {
Self {
aabb: aabb.to_owned(),
mass: 1.0,
friction: 1.0,
gravity_multiplier: 1.0,
auto_step: false,
..Default::default()
}
}
/// Configure the mass of this rigid body. Default is 1.0.
pub fn mass(mut self, mass: f32) -> Self {
self.mass = mass;
self
}
/// Configure the friction of this rigid body. Default is 1.0.
pub fn friction(mut self, friction: f32) -> Self {
self.friction = friction;
self
}
pub fn restitution(mut self, restitution: f32) -> Self {
self.restitution = restitution;
self
}
pub fn gravity_multiplier(mut self, gravity_multiplier: f32) -> Self {
self.gravity_multiplier = gravity_multiplier;
self
}
pub fn auto_step(mut self, auto_step: bool) -> Self {
self.auto_step = auto_step;
self
}
pub fn build(self) -> RigidBody {
RigidBody {
collision: None,
stepped: false,
air_drag: -1.0,
fluid_drag: -1.0,
resting: Vec3::default(),
velocity: Vec3::default(),
in_fluid: false,
ratio_in_fluid: 0.0,
forces: Vec3::default(),
impulses: Vec3::default(),
sleep_frame_count: 10 | 0,
aabb: self.aabb,
mass: self.mass,
friction: self.friction,
restitution: self.restitution,
gravity_multiplier: self.gravity_multiplier,
auto_step: self.auto_step,
}
}
}