问题
我正在开发一个简单的 OpenGL 项目。我的目标是从受影响的物体上正确地反射一个受力的物体。
为此,我使用形状的线段(线段是组成一条线的两个点)进行碰撞检测。例如,正方形的段将是:
self.segments = [
Segment2D(self.bottom_left, self.bottom_right), # Bottom side
Segment2D(self.bottom_right, self.top_right), # Right side
Segment2D(self.top_right, self.top_left), # Top side
Segment2D(self.top_left, self.bottom_left) # Left side
]
检测的工作原理是检查对象的任何片段是否与外部对象的片段相交。我正在使用 geeksforgeeks 中解释的方法:https ://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
- d : 力向量
- b : 受影响的表面矢量
- n : 撞击表面上的归一化(单位向量)法线向量 90 度
- r : 力向量的反射向量
然而; 在发现一个物体与另一个物体发生碰撞后,找到这个反射向量就会出现问题。
例如,当两个正方形发生碰撞(我实现的唯一形状)时,碰撞检测有时会检测到两个段上的碰撞。因为我不知道我应该如何选择哪一个作为受影响的部分,所以反射有时会出现在错误的方向上。
问题
如何确定图像中绿色的哪一部分应该用作反射的影响矢量?
编辑:
我现在已经实施了 Blindman67 建议的解决方案。碰撞检测(决定碰撞哪一侧)似乎在大约 80% 的情况下有效。当靠近角落碰撞时,正方形有时仍会反射到错误的方向。我不确定这是我的错误还是给定的解决方案。
我一直无法解决问题。
此外,当受影响的方格在两侧被吞下时,检查不再成立,使受影响的线彼此平行。
这是我想出的逻辑:
def rect_rect_collision(self, other, force: Vector2D, segments: List[Segment2D]) -> Segment2D:
"""
Returns the segment that is the most correct one for collision
:param other: Colliding RigidBody
:param force: The force applied on the object
:param segments: The segments that were detected as colliding by the general detection
:return: The correct collision segment
"""
if segments[0].angle() == segments[1].angle():
# TODO: decide which to collide of the remaining 2
raise Exception("Lines are parallel")
# Shared corner of the impacted segments
common_corner = RigidRect2D.get_common_corner(segments[0], segments[1])
E: Point2D = self.add_width_height_relative_to_center(common_corner, other.shape.center)
# Segment 0 is EF
seg_0_other = segments[0].p1 if segments[0].p2 == common_corner else segments[0].p2
F: Point2D = self.add_width_height_relative_to_center(seg_0_other, other.shape.center)
# Segment 1 is EJ
seg_1_other = segments[1].p1 if segments[1].p2 == common_corner else segments[1].p2
J: Point2D = self.add_width_height_relative_to_center(seg_1_other, other.shape.center)
A: Point2D = self.shape.center
ABx: float = force.x
ABy: float = force.y
uu = ABx * (A.y - E.y) - ABy * (A.x - E.x)
EFx = F.x - E.x
EFy = F.y - E.y
c = ABx * EFy - ABy * EFx
if c != 0:
u = uu / c
print("U - EF: ", u)
if 0 <= u <= 1:
# Hits line E-F
return segments[0]
EJx = J.x - E.x
EJy = J.y - E.y
c = ABx * EJy - ABy * EJx
if c != 0:
u = uu / c
print("U - EJ: ", u)
if 0 <= u <= 1:
# Hits line E-J
return segments[1]
raise Exception("Returned no segment from the collision detection")
@staticmethod
def get_common_corner(segment1: Segment2D, segment2: Segment2D):
if segment1.has_point(segment2.p1):
return segment2.p1
if segment1.has_point(segment2.p2):
return segment2.p2
print(segment1)
print(segment2)
raise Exception("No common corner")
def add_width_height_relative_to_center(self, point: Point2D, center: Point2D) -> Point2D:
newPoint = Point2D(point.x, point.y)
if newPoint.y >= center.y:
newPoint.y += self.shape.height / 2
else:
newPoint.y -= self.shape.height / 2
if newPoint.x >= center.x:
newPoint.x += self.shape.width / 2
else:
newPoint.x -= self.shape.width / 2
return newPoint
这是一个图像,描述了反射方法从 rect_rect_collision 方法接收到的不正确的影响向量:
绿色轮廓是可碰撞的刚体,红色箭头是反射前的力矢量方向。计算反射后,反射将在错误的方向。