1use std::rc::Rc;
2
3use super::{
4 body::Body,
5 math::{Mat2x2, Vec2},
6 world::World,
7};
8
9#[derive(Debug, Clone, Copy)]
10pub struct Joint {
11 mass_matrix: Mat2x2,
13
14 local_anchor1: Vec2,
15 local_anchor2: Vec2,
16
17 r1: Vec2,
18 r2: Vec2,
19 bias: Vec2,
20
21 accumulated_impulse: Vec2,
23 bias_factor: f32,
24 softness: f32,
25}
26
27impl Joint {
28 pub fn new(body1: &mut Body, body2: &mut Body, anchor: Vec2) -> Self {
29 let rot1 = Mat2x2::from_angle(body1.rotation);
30 let rot2 = Mat2x2::from_angle(body2.rotation);
31 let rot1_t = rot1.transpose();
32 let rot2_t = rot2.transpose();
33
34 let local_anchor1 = rot1_t * (anchor - body1.position);
35 let local_anchor2 = rot2_t * (anchor - body2.position);
36
37 Self {
38 mass_matrix: Mat2x2::ZERO,
39 local_anchor1,
40 local_anchor2,
41 r1: Vec2::ZERO,
42 r2: Vec2::ZERO,
43 bias: Vec2::ZERO,
44 accumulated_impulse: Vec2::ZERO,
45 bias_factor: 0.2,
46 softness: 0.0,
47 }
48 }
49
50 pub fn pre_step(
51 &mut self,
52 body1: &mut Body,
53 body2: &mut Body,
54 inv_dt: f32,
55 ) {
56 let rot1 = Mat2x2::from_angle(body1.rotation);
58 let rot2 = Mat2x2::from_angle(body2.rotation);
59
60 self.r1 = rot1 * self.local_anchor1;
61 self.r2 = rot2 * self.local_anchor2;
62
63 let body1_inv_i = body1.inv_moment_of_inertia;
76 let body2_inv_i = body2.inv_moment_of_inertia;
77 let k1 = Mat2x2::new(
78 body1.inv_mass + body2.inv_mass,
79 0.0,
80 0.0,
81 body1.inv_mass + body2.inv_mass,
82 );
83 let k2 = Mat2x2::new(
84 body1_inv_i * self.r1.y * self.r1.y,
85 -body1_inv_i * self.r1.x * self.r1.y,
86 -body1_inv_i * self.r1.x * self.r1.y,
87 body1_inv_i * self.r1.x * self.r1.x,
88 );
89 let k3 = Mat2x2::new(
90 body2_inv_i * self.r2.y * self.r2.y,
91 -body2_inv_i * self.r2.x * self.r2.y,
92 -body2_inv_i * self.r2.x * self.r2.y,
93 body2_inv_i * self.r2.x * self.r2.x,
94 );
95 let k = k1 + k2 + k3 + Mat2x2::from_diag(Vec2::splat(self.softness));
96
97 self.mass_matrix = k.invert();
98
99 let p1 = body1.position + self.r1;
100 let p2 = body2.position + self.r2;
101 let dp = p2 - p1;
102
103 if World::POSITION_CORRECTION {
104 self.bias = -self.bias_factor * inv_dt * dp;
105 } else {
106 self.bias = Vec2::ZERO;
107 }
108
109 if World::WARM_STARTING {
110 body1.velocity -= body1.inv_mass * self.accumulated_impulse;
112 body1.angular_velocity -= body1.inv_moment_of_inertia
113 * self.r1.cross(self.accumulated_impulse);
114
115 body2.velocity += body2.inv_mass * self.accumulated_impulse;
116 body2.angular_velocity += body2.inv_moment_of_inertia
117 * self.r2.cross(self.accumulated_impulse);
118 } else {
119 self.accumulated_impulse = Vec2::ZERO;
120 }
121 }
122
123 pub fn apply_impulse(&mut self, body1: &mut Body, body2: &mut Body) {
124 let dv = body2.velocity
125 + Vec2::scalar_cross(body2.angular_velocity, self.r2)
126 - body1.velocity
127 - Vec2::scalar_cross(body1.angular_velocity, self.r1);
128
129 let impulse = self.mass_matrix
130 * (-dv - self.bias - self.softness * self.accumulated_impulse);
131
132 body1.velocity -= body1.inv_mass * impulse;
133 body1.angular_velocity -=
134 body1.inv_moment_of_inertia * self.r1.cross(impulse);
135
136 body2.velocity += body2.inv_mass * impulse;
137 body2.angular_velocity +=
138 body2.inv_moment_of_inertia * self.r2.cross(impulse);
139
140 self.accumulated_impulse += impulse;
141 }
142}