跳到主要内容

碰撞事件

两个刚体接触时,物理引擎会向双方实体报告。可以播放音效、施加伤害、生成粒子或改变游戏状态。相关实体的 collision 和 rigidbody 都会发出事件,选择方便的组件监听即可。

事件​

事件触发时机处理函数参数
collisionstart开始接触的物理步中触发一次ContactResult
contact保持接触期间每个物理步ContactResult
collisionend停止接触时触发一次对方 Entity

只有至少一方为动态刚体时才报告接触,静态和运动学彼此不碰撞。与触发体积重叠时发出的是 triggerenter 和 triggerleave。

监听碰撞​

使用 on 订阅,会返回 EventHandle。保留句柄,不再需要时调用其 off();也可在组件上调用 off(eventName, callback),传入相同回调,见事件。碰撞音效等一次性反应用 collisionstart,逐步更新接触详情则用 contact:

const handle = entity.collision.on('collisionstart', (result) => {
console.log(`${entity.name} hit ${result.other.name}`);
});

// Later, when the entity is destroyed or the listener is no longer wanted
handle.off();

代码位置取决于开发方式:

实体具有组件后订阅,或像编辑器标签页所示附加脚本,见脚本编程。

接触数据​

collisionstart 和 contact 传入 ContactResult,包含:

  • other:碰撞的另一个实体。
  • contacts:ContactPoint 数组,对应两个形状的各接触点。

每个接触点包含:

属性说明
point当前实体上的世界空间接触点
pointOther对方实体上的世界空间接触点
localPoint当前实体局部空间中的接触点
localPointOther对方实体局部空间中的接触点
normal世界空间接触法线,从接触点朝远离对方表面的方向指向
impulse物理引擎为分离刚体施加的冲量,越大表示撞击越强

冲量适合衡量碰撞强度,可据此调整音量或伤害,并忽略轻微擦碰:

entity.collision.on('collisionstart', (result) => {
let strongest = 0;
for (const contact of result.contacts) {
strongest = Math.max(strongest, contact.impulse);
}
if (strongest > 5) {
entity.sound.play('crash');
}
});

场景范围的接触​

若要在中央音频或伤害管理器中统一处理,监听刚体组件系统的 contact,而非各实体。每个接触点触发一次,传入同时包含两个实体的 SingleContactResult:

app.systems.rigidbody.on('contact', (result) => {
// result.a and result.b are the two entities
// result.pointA, result.pointB and result.normal are in world space
if (result.impulse > 5) {
console.log(`${result.a.name} and ${result.b.name} collided hard`);
}
});
提示

只要两个刚体接触,contact 每个物理步都会触发,盒子静置在地板上也会持续触发。一次性效果优先使用 collisionstart,并保持 contact 处理函数轻量。

另请参阅​