对于动画碰撞对象的碰撞必须手动处理. 一个想当然的处理方法如下:
function on_message(self, message_id, message, sender)
-- 处理碰撞
if message_id == hash("contact_point_response") then
local newpos = go.get_position() + message.normal * message.distance
go.set_position(newpos)
end
end
动画碰撞对象的确离开了碰撞穿透, 但是分离之后经常会过冲, 这在许多情况下会产生抖动. 为了便于理解, 想象游戏主角碰到了两个物体, A 和 B:
碰撞发生的那一帧里, 物理引擎发出多个 "contact_point_response"
消息, 一个给 A 一个给 B. 如果按上面那样移动角色, 结果会是这样:
顺序无所谓结果是一样的: 最终位移是 每个穿透向量的矢量和:
要想正确地将角色移出 A 和 B, 需要处理碰撞点的穿透距离并检测上一个位移是否, 完全或部分, 分离了它们.
假设第一次碰撞从 A 开始, 然后针对 A 做位移:
这样一来角色也部分离开了 B. 最后只剩下 B 黑色箭头那点穿透. 这段位移应该是 A 向量映射到 B 剩余的补偿:
l = vmath.project(A, B) * vmath.length(B)
补偿向量等于 B 向量减去 l 向量. 所以计算位移的时候, 对于每个碰撞点, 可以引入矫正向量按以下步骤进行矫正:
完整的代码实现如下:
function init(self)
-- 校正向量
self.correction = vmath.vector3()
end
function update(self, dt)
-- 重置矫正向量
self.correction = vmath.vector3()
end
function on_message(self, message_id, message, sender)
-- 处理碰撞
if message_id == hash("contact_point_response") then
-- 获取位移计算所需数据.
-- 当前帧可能有多个碰撞点需要处理,
-- 通过累积矫正向量,
-- 达到正确计算位移的目的:
if message.distance > 0 then
-- 第一步, 把矫正向量投射到
-- 穿透向量上.
local proj = vmath.project(self.correction, message.normal * message.distance)
if proj < 1 then
-- 没有过冲的才需要补偿.
local comp = (message.distance - message.distance * proj) * message.normal
-- 应用补偿向量.
go.set_position(go.get_position() + comp)
-- 积累矫正向量.
self.correction = self.correction + comp
end
end
end
end
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB