This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English
キネマティックコリジョンオブジェクト(kinematic collision object)を使う場合は、自分で衝突を解決し、その応答としてオブジェクトを移動する必要があります。衝突している2つのオブジェクトを分離する単純な実装は、次のようになります。
function on_message(self, message_id, message, sender)
-- Handle collision
if message_id == hash("contact_point_response") then
local newpos = go.get_position() + message.normal * message.distance
go.set_position(newpos)
end
end
このコードは、キネマティックオブジェクトを、めり込んでいる他の物理オブジェクトから分離します。ただし、分離のための移動量が過剰になることが多く、多くの場合に小刻みな揺れが見られます。この問題をよりよく理解するために、プレイヤーキャラクターが2つのオブジェクト A と B に衝突した次の例を考えてみます。

物理エンジンは、衝突が発生したフレームに複数の "contact_point_response" メッセージを送信します。オブジェクト A について1つ、オブジェクト B について1つです。上記の単純なコードのように、それぞれのめり込みに応じてキャラクターを移動すると、次のように分離されます。
この順序は任意ですが、どちらの順序でも結果は同じです。分離のための移動量の合計は、個々のめり込みベクトルの和 になります。

キャラクターをオブジェクト A と B から適切に分離するには、各接触点(contact point)のめり込み距離を処理し、それ以前の分離によって、分離がすでに全体的または部分的に解決されていないかを確認する必要があります。
最初の接触点メッセージがオブジェクト A から届き、A のめり込みベクトルだけキャラクターを外へ移動したとします。

この時点で、キャラクターは B からもすでに部分的に分離されています。オブジェクト B から完全に分離するために必要な最後の補償量を、上図の黒い矢印で示しています。補償ベクトルの長さは、A のめり込みベクトルを B のめり込みベクトルに射影することで計算できます。

l = vmath.project(A, B) * vmath.length(B)
補償ベクトルは、B の長さを l だけ減らすことで求められます。任意の数のめり込みについてこれを計算するには、長さがゼロの補正ベクトルから始めて、接触点ごとに次の処理を行い、必要な補正量をベクトルに累積します。
完全な実装は次のようになります。
function init(self)
-- correction vector
self.correction = vmath.vector3()
end
function update(self, dt)
-- reset correction
self.correction = vmath.vector3()
end
function on_message(self, message_id, message, sender)
-- Handle collision
if message_id == hash("contact_point_response") then
-- Get the info needed to move out of collision. We might
-- get several contact points back and have to calculate
-- how to move out of all of them by accumulating a
-- correction vector for this frame:
if message.distance > 0 then
-- First, project the accumulated correction onto
-- the penetration vector
local proj = vmath.project(self.correction, message.normal * message.distance)
if proj < 1 then
-- Only care for projections that does not overshoot.
local comp = (message.distance - message.distance * proj) * message.normal
-- Apply compensation
go.set_position(go.get_position() + comp)
-- Accumulate correction done
self.correction = self.correction + comp
end
end
end
end