Определите точку столкновения, проверив вектор движения к стене. Если вы знаете что-то о своей поверхности (например, как вы говорите, это часть коробки), вы можете протестировать сразу несколько стен.
Решение может немного отличаться между 2D и 3D. Я пойду с 2D, так как вы говорите «квадрат», а не «куб» или «коробка».
Как только вы узнаете, где находится ваша точка, вы берете оставшуюся часть вектора движения, расставляете точки против направления стены (вычитаете одну точку на стене из другой, затем нормализуетесь), затем масштабируете направление стены на эту величину. Это количество движения, которое будет параллельно стене, при условии отсутствия трения.
Редактировать добавил следующий код:
шаблонный:
import math
class Vector2d:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, rhs):
return Vector2d(self.x + rhs.x, self.y + rhs.y)
def __sub__(self, rhs):
return Vector2d(self.x - rhs.x, self.y - rhs.y)
def GetScaled(self, scale):
return Vector2d(self.x * scale, self.y * scale)
def GetLength(self):
return math.sqrt((self.x * self.x) + (self.y * self.y))
def GetNormalized(self):
return self.GetScaled(1.0 / self.GetLength())
def DotProduct(v0, v1):
return (v0.x * v1.x) + (v0.y * v1.y)
Реальный бизнес:
class Wall2d:
def init(self, point0, point1):
"""point0, point1 are Vector2ds"""
self.p0 = point0
self.p1 = point1
# these three steps could be combined to optimize, but
# for demonstration are left explicit
self.dir = self.p1 - self.p0
self.length = self.dir.GetLength()
self.dir = self.dir.GetNormalized()
# computing the normal in 3D would require three points
# on the face and a cross product
self.normal = Vector2d(self.length.y, -self.length.x)
def LineSegmentCollides(self, pointStart, pointEnd):
startDot = DotProduct(pointStart - self.p0, self.normal)
endDot = DotProduct(pointEnd - self.p0, self.normal)
if startDot * endDot < 0:
# the only way a collision can occur is if the start
# and end are on opposite sides of the wall, so their
# dot product results will have opposite signs, so
# the result of the multiplication is negative
moveVector = pointEnd - pointStart
# scale the movement vector by the ratio of the move
# vector on the "start" side versus the total length
# of the movement in the axis of the normal
collisionDelta = moveVector.GetScaled(startDot /
(startDot + endDot))
collisionPoint = pointStart + collisionDelta
collisionDot = DotProduct(collisionPoint - self.p0, self.dir)
if (collisionDot > 0) && (collisionDot < self.length):
# we've hit the wall between p0 and p1 (other
# values of collisionDot mean we missed on one
# end or the other)
# now, collision response is up to you. In this
# case, we'll just zero out the movement in the
# direction of the wall after the collision
# (sorry about the poor naming)
# note that we don't actually care about the actual
# point of collision here.
collisionPushBack = moveVector.GetScaled(
endDot / (startDot + endDot))
endPoint = pointEnd + collisionPushBack
return True
return False
Надеюсь, это полезно.