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
Quando usi oggetti di collisione cinematici, devi risolvere le collisioni autonomamente e spostare gli oggetti di conseguenza. Un’implementazione elementare per separare due oggetti in collisione è la seguente:
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
Questo codice separa il tuo oggetto cinematico dagli altri oggetti fisici in cui penetra, ma spesso lo spostamento è eccessivo e in molti casi vedrai delle oscillazioni. Per capire meglio il problema, considera il seguente caso in cui il personaggio del giocatore è entrato in collisione con due oggetti, A e B:

Nel fotogramma in cui si verifica la collisione, il motore fisico invia più messaggi "contact_point_response", uno per l’oggetto A e uno per l’oggetto B. Se sposti il personaggio in risposta a ciascuna penetrazione, come nel codice elementare riportato sopra, la separazione risultante sarà:
L’ordine di queste operazioni è arbitrario, ma il risultato è lo stesso in entrambi i casi: una separazione totale pari alla somma dei singoli vettori di penetrazione:

Per separare correttamente il personaggio dagli oggetti A e B, devi gestire la distanza di penetrazione di ciascun punto di contatto e verificare se le separazioni precedenti hanno già prodotto, in tutto o in parte, la separazione necessaria.
Supponi che il primo messaggio di contatto provenga dall’oggetto A e che tu sposti il personaggio verso l’esterno usando il vettore di penetrazione di A:

A questo punto il personaggio è già stato parzialmente separato da B. La compensazione finale necessaria per ottenere la separazione completa dall’oggetto B è indicata dalla freccia nera qui sopra. Puoi calcolare la lunghezza del vettore di compensazione proiettando il vettore di penetrazione di A sul vettore di penetrazione di B:

l = vmath.project(A, B) * vmath.length(B)
Il vettore di compensazione si ottiene riducendo di l la lunghezza di B. Per eseguire questo calcolo con un numero qualsiasi di penetrazioni, puoi accumulare la correzione necessaria in un vettore. Parti da un vettore di correzione di lunghezza zero e, per ciascun punto di contatto:
Ecco un’implementazione completa:
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