一般的な用語と疑似コードで言えば、壁が実際にポイントが衝突している正方形全体の一部である場合、壁に沿ってスライドするという衝突応答を持つ最良の方法は何でしょうか? 使用される衝突テスト方法は、点が正方形内にあるかどうかを確認するためのテストです。
正方形を 4 つの線に分割し、線までの最短距離を計算してから、その距離だけポイントを移動する必要がありますか?そうであれば、衝突後にポイントが最も近い正方形のエッジをどのように判断できますか?
一般的な用語と疑似コードで言えば、壁が実際にポイントが衝突している正方形全体の一部である場合、壁に沿ってスライドするという衝突応答を持つ最良の方法は何でしょうか? 使用される衝突テスト方法は、点が正方形内にあるかどうかを確認するためのテストです。
正方形を 4 つの線に分割し、線までの最短距離を計算してから、その距離だけポイントを移動する必要がありますか?そうであれば、衝突後にポイントが最も近い正方形のエッジをどのように判断できますか?
壁に対する移動ベクトルをテストして衝突点を検出します。表面について知っている場合 (たとえば、箱の一部であると言う場合) は、一度に複数の壁をテストできる場合があります。
ソリューションは、2D と 3D の間でわずかに異なる場合があります。「立方体」や「箱」ではなく「正方形」を話しているので、2D を使用します。
ポイントがどこに当たっているかがわかったら、移動ベクトルの残りを取り、壁の方向に対して点を付け (壁の 1 つのポイントを別のポイントから引き、正規化します)、その量だけ壁の方向をスケーリングします。これは、摩擦がないと仮定した場合に、壁に平行な動きの量です。
編集により、次のコードが追加されました。
ボイラープレート:
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
それが役に立つことを願っています。