arcane_engine/physics/
constraints.rs1use super::types::{BodyType, Constraint, RigidBody};
2
3pub fn solve_constraints(
5 bodies: &mut [Option<RigidBody>],
6 constraints: &[Constraint],
7 _dt: f32,
8) {
9 for constraint in constraints {
10 match constraint {
11 Constraint::Distance {
12 body_a,
13 body_b,
14 distance,
15 anchor_a,
16 anchor_b,
17 ..
18 } => solve_distance(bodies, *body_a, *body_b, *distance, *anchor_a, *anchor_b),
19 Constraint::Revolute {
20 body_a,
21 body_b,
22 pivot,
23 ..
24 } => solve_revolute(bodies, *body_a, *body_b, *pivot),
25 }
26 }
27}
28
29fn solve_distance(
30 bodies: &mut [Option<RigidBody>],
31 id_a: u32,
32 id_b: u32,
33 target_distance: f32,
34 anchor_a: (f32, f32),
35 anchor_b: (f32, f32),
36) {
37 let a_idx = id_a as usize;
38 let b_idx = id_b as usize;
39
40 let (xa, ya, cos_a, sin_a, inv_ma, type_a) = match &bodies[a_idx] {
41 Some(b) => (b.x, b.y, b.angle.cos(), b.angle.sin(), b.inv_mass, b.body_type),
42 None => return,
43 };
44 let (xb, yb, cos_b, sin_b, inv_mb, type_b) = match &bodies[b_idx] {
45 Some(b) => (b.x, b.y, b.angle.cos(), b.angle.sin(), b.inv_mass, b.body_type),
46 None => return,
47 };
48
49 if type_a != BodyType::Dynamic && type_b != BodyType::Dynamic {
50 return;
51 }
52
53 let wa_x = xa + anchor_a.0 * cos_a - anchor_a.1 * sin_a;
55 let wa_y = ya + anchor_a.0 * sin_a + anchor_a.1 * cos_a;
56 let wb_x = xb + anchor_b.0 * cos_b - anchor_b.1 * sin_b;
57 let wb_y = yb + anchor_b.0 * sin_b + anchor_b.1 * cos_b;
58
59 let dx = wb_x - wa_x;
60 let dy = wb_y - wa_y;
61 let current_distance = (dx * dx + dy * dy).sqrt();
62
63 if current_distance < 1e-8 {
64 return;
65 }
66
67 let nx = dx / current_distance;
68 let ny = dy / current_distance;
69 let error = current_distance - target_distance;
70
71 let inv_total = inv_ma + inv_mb;
72 if inv_total == 0.0 {
73 return;
74 }
75
76 let correction = error / inv_total;
77
78 if let Some(a) = &mut bodies[a_idx] {
79 if a.body_type == BodyType::Dynamic {
80 a.x += correction * inv_ma * nx;
81 a.y += correction * inv_ma * ny;
82 }
83 }
84 if let Some(b) = &mut bodies[b_idx] {
85 if b.body_type == BodyType::Dynamic {
86 b.x -= correction * inv_mb * nx;
87 b.y -= correction * inv_mb * ny;
88 }
89 }
90}
91
92fn solve_revolute(
93 bodies: &mut [Option<RigidBody>],
94 id_a: u32,
95 id_b: u32,
96 pivot: (f32, f32),
97) {
98 let a_idx = id_a as usize;
99 let b_idx = id_b as usize;
100
101 let (xa, ya, inv_ma, type_a) = match &bodies[a_idx] {
102 Some(b) => (b.x, b.y, b.inv_mass, b.body_type),
103 None => return,
104 };
105 let (xb, yb, inv_mb, type_b) = match &bodies[b_idx] {
106 Some(b) => (b.x, b.y, b.inv_mass, b.body_type),
107 None => return,
108 };
109
110 if type_a != BodyType::Dynamic && type_b != BodyType::Dynamic {
111 return;
112 }
113
114 let mid_x = (xa + xb) * 0.5;
118 let mid_y = (ya + yb) * 0.5;
119 let _ = mid_x;
120 let _ = mid_y;
121
122 let err_ax = pivot.0 - xa;
124 let err_ay = pivot.1 - ya;
125 let err_bx = pivot.0 - xb;
127 let err_by = pivot.1 - yb;
128
129 let inv_total = inv_ma + inv_mb;
130 if inv_total == 0.0 {
131 return;
132 }
133
134 let _ = err_ax;
137 let _ = err_ay;
138 let _ = err_bx;
139 let _ = err_by;
140
141 if let Some(a) = &mut bodies[a_idx] {
160 if a.body_type == BodyType::Dynamic {
161 let dx = pivot.0 - a.x;
162 let dy = pivot.1 - a.y;
163 a.x += dx * inv_ma / inv_total;
164 a.y += dy * inv_ma / inv_total;
165 }
166 }
167 if let Some(b) = &mut bodies[b_idx] {
168 if b.body_type == BodyType::Dynamic {
169 let dx = pivot.0 - b.x;
170 let dy = pivot.1 - b.y;
171 b.x += dx * inv_mb / inv_total;
172 b.y += dy * inv_mb / inv_total;
173 }
174 }
175}