Скользящий ответ после столкновения точки с квадратом - PullRequest
0 голосов
/ 19 марта 2010

В общих чертах и ​​псевдокоде, каков наилучший способ получить реакцию столкновения, скользящую вдоль стены, если стена фактически является лишь частью целого квадрата, с которым сталкивается точка?Используемый метод проверки на столкновение является проверкой, находится ли точка в квадрате.

Должен ли я разделить квадрат на четыре линии и просто вычислить кратчайшее расстояние до линии, а затем переместить точку обратно на это расстояние?Если так, то как я могу определить, какой край квадрата точка ближе всего после столкновения?

1 Ответ

2 голосов
/ 19 марта 2010

Определите точку столкновения, проверив вектор движения к стене. Если вы знаете что-то о своей поверхности (например, как вы говорите, это часть коробки), вы можете протестировать сразу несколько стен.

Решение может немного отличаться между 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

Надеюсь, это полезно.

...