Skip to content

Commit be03532

Browse files
committed
Add pre_solve to DistanceJoint and fix Island solver
- Add pre_solve method to DistanceJoint for computing world anchors, direction, and Baumgarte bias before constraint solving - Add hasattr checks in Island.solve to handle joints with optional solver methods - Pass time_step to solve_velocity_constraints - Remove redundant joint position correction loop from World.step - Adjust contact separation threshold and reset normal_impulse when bodies are moving apart
1 parent 1419f33 commit be03532

4 files changed

Lines changed: 32 additions & 15 deletions

File tree

src/collision/contact.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def resolve(self, dt):
110110
logger.info(f"Baumgarte bias: {bias:.4f}")
111111

112112
# Calculate normal impulse scalar with warm starting
113-
j = -(1 + e) * velocity_along_normal + bias
113+
j = -(1 + e) * velocity_along_normal + bias # direct + bias
114114
j += self.normal_impulse # Warm starting
115115

116116
# Remove or reduce min_impulse to prevent over-correction
@@ -129,8 +129,8 @@ def resolve(self, dt):
129129
j = max(j, 0.0)
130130

131131
# Check if bodies are moving apart
132-
if velocity_along_normal > 0.0: # moving apart
133-
logger.info("Bodies are moving apart, skipping impulse application")
132+
if velocity_along_normal > 0.01: # moving apart
133+
self.normal_impulse = 0.0
134134
return 0.0
135135

136136
# Apply normal impulse

src/constraints/distance.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,27 @@ def solve_position_constraints(self):
157157
self.body2.inverse_inertia * self.anchor2.cross(impulse_vector)
158158
)
159159

160+
def pre_solve(self, time_step: float):
161+
"""
162+
Prepare for solving (compute world anchors, bias, etc.).
163+
"""
164+
# World anchors
165+
self.world_anchor1 = self.body1.position + self.anchor1
166+
self.world_anchor2 = self.body2.position + self.anchor2
167+
168+
# Direction and current length
169+
self.direction = self.world_anchor2 - self.world_anchor1
170+
self.current_length = (
171+
self.direction.magnitude() if self.direction.magnitude() > 1e-6 else 1.0
172+
)
173+
self.direction = self.direction / self.current_length
174+
175+
# Bias for position error (Baumgarte)
176+
position_error = self.current_length - self.length
177+
self.bias = (
178+
-(0.2 / time_step) * position_error * self.direction
179+
) # negative to correct
180+
160181
def get_reaction_force(self, dt: float) -> Vec2:
161182
"""
162183
Get the reaction force of the distance joint.

src/dynamics/island.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,22 @@ def solve(self, time_step):
6666
time_step (float): The time step for the simulation.
6767
"""
6868
for joint in self.joints:
69-
joint.pre_solve(time_step)
69+
if hasattr(joint, "pre_solve"):
70+
joint.pre_solve(time_step)
7071

7172
for _ in range(8):
7273
for contact in self.contacts:
7374
contact.resolve()
7475

7576
for joint in self.joints:
76-
joint.solve_velocity_constraints()
77+
if hasattr(joint, "solve_velocity_constraints"):
78+
joint.solve_velocity_constraints(time_step)
7779

7880
for _ in range(3):
7981
for joint in self.joints:
80-
joint.solve_position_constraints()
82+
if hasattr(joint, "solve_position_constraints"):
83+
joint.solve_position_constraints()
8184

8285
for joint in self.joints:
83-
joint.post_solve()
86+
if hasattr(joint, "post_solve"):
87+
joint.post_solve()

src/dynamics/world.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,6 @@ def step(
246246
f"Total impulse applied this step: {total_impulse_magnitude:.4f}\n"
247247
)
248248

249-
# Correct positions (joints)
250-
for _ in range(self.position_iterations):
251-
for joint in self.joints:
252-
if hasattr(joint, "pre_solve"):
253-
joint.pre_solve(self.time_step)
254-
if hasattr(joint, "solve_position_constraints"):
255-
joint.solve_position_constraints()
256-
257249
def _solve_contacts(self, collision_pairs, dt):
258250
"""
259251
Solve contacts using the contact solver with persistence.

0 commit comments

Comments
 (0)