ignore linear impulse if bodies are separating

This commit is contained in:
=
2026-03-13 00:55:01 -04:00
parent c7fd7f0d25
commit 0ff308e110
5 changed files with 81 additions and 115 deletions

View File

@@ -16,18 +16,18 @@ def _collide_circle_circle(a: CircleCollider, b: CircleCollider, a_transform: Tr
return None
normal = delta.normalize()
return ColliderContact(
point=a_transform.global_position + normal * b.radius,
points=[a_transform.global_position - normal * b.radius],
normal=normal,
penetration=radii - dist,
)
def _collide_convex_circle(a: ConvexCollider, b: CircleCollider, a_transform: Transform, b_transform: Transform) -> ColliderContact | None:
hull = a.hull(a_transform)
normals = [face.normal for face in hull.faces()]
circle_normal = min([(b_transform.global_position - v) for v in hull.vertices()], key=lambda v: v.length()).normalize()
normals.append(circle_normal)
collision_normal: pg.Vector2 | None = None
closest_vertex = hull.closest_vertex(b_transform.global_position)
circle_normal = (b_transform.global_position-closest_vertex).normalize()
normals = [*[face.normal for face in hull.faces()], circle_normal]
lowest_pen = float('inf')
collision_normal = None
for normal in normals:
center_proj = normal.dot(b_transform.global_position)
circle_interval = (center_proj - b.radius, center_proj + b.radius)
@@ -35,11 +35,11 @@ def _collide_convex_circle(a: ConvexCollider, b: CircleCollider, a_transform: Tr
penetration = _interval_overlap(circle_interval, convex_interval)
if penetration is None:
return None
if penetration < lowest_pen:
if penetration < lowest_pen and (a_transform.position - b_transform.position).dot(normal) < 0:
lowest_pen = penetration
collision_normal = normal
collision_normal = -1 * normal #struggling to keep the convention correct but whatever
return ColliderContact(
points=[b_transform.global_position - b.radius*normal],
points=[b_transform.global_position + b.radius*collision_normal],
normal=collision_normal,
penetration=lowest_pen
)
@@ -80,9 +80,12 @@ def _collide_convex_convex(a: ConvexCollider, b: ConvexCollider, a_transform: Tr
if d2 > 0:
contact_manifold[1] = contact_manifold[1] + (d2 / (d2 - d1)) * (contact_manifold[0] - contact_manifold[1])
clip(right_normal, ref_face.end)
clip(left_normal, ref_face.begin)
clip(ref_face.normal, ref_face.begin)
try:
clip(right_normal, ref_face.end)
clip(left_normal, ref_face.begin)
clip(ref_face.normal, ref_face.begin)
except:
return None
return ColliderContact(
points=contact_manifold,

View File

@@ -42,6 +42,9 @@ class PolygonalHull:
def project(self, axis: pg.Vector2) -> tuple[float, float]:
projections = [v.dot(axis) for v in self._vertices]
return (min(projections), max(projections))
def closest_vertex(self, v: pg.Vector2) -> pg.Vector2:
return min(self._vertices, key=lambda p: (v-p).length())
class BaseCollider(ABC):