监听碰撞事件和获取碰撞信息
在物理仿真中,了解刚体之间的碰撞信息是非常关键的。Cannon.js 提供了 collide
事件,让我们能够在碰撞发生时捕获相关信息,比如碰撞对象、冲击速度等。
一、监听碰撞事件
body.addEventListener('collide', (event) => {
console.log('发生碰撞!')
console.log('碰撞到的刚体:', event.body)
console.log('碰撞强度:', event.contact.getImpactVelocityAlongNormal())
})
字段 | 含义 |
---|---|
event.body | 与当前刚体发生碰撞的刚体 |
event.contact | 碰撞联系信息 |
getImpactVelocityAlongNormal() | 获取法向方向上的冲击速度(衡量碰撞强度) |
二、完整示例
球体从空中落下与地面发生碰撞,并在控制台打印碰撞信息:
<!-- App.vue -->
<script setup>
import { onMounted, ref } from 'vue'
import * as THREE from 'three'
import * as CANNON from 'cannon-es'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
const canvasRef = ref()
onMounted(() => {
// 创建 Three.js 场景与相机
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100)
camera.position.set(0, 5, 10)
// 渲染器和轨道控制器
const renderer = new THREE.WebGLRenderer({ canvas: canvasRef.value })
renderer.setSize(window.innerWidth, window.innerHeight)
const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true
// 灯光
const light = new THREE.DirectionalLight(0xffffff, 1)
light.position.set(10, 10, 10)
scene.add(light)
// 创建物理世界
const world = new CANNON.World()
world.gravity.set(0, -9.82, 0)
// 创建地面刚体
const groundBody = new CANNON.Body({
mass: 0,
shape: new CANNON.Plane()
})
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0)
world.addBody(groundBody)
// 创建地面网格
const groundGeo = new THREE.PlaneGeometry(10, 10)
const groundMat = new THREE.MeshStandardMaterial({ color: 0x999999, side: THREE.DoubleSide })
const groundMesh = new THREE.Mesh(groundGeo, groundMat)
groundMesh.rotation.x = -Math.PI / 2
scene.add(groundMesh)
// 创建小球
const radius = 0.5
const sphereGeo = new THREE.SphereGeometry(radius, 32, 32)
const sphereMat = new THREE.MeshStandardMaterial({ color: 0x0077ff })
const sphereMesh = new THREE.Mesh(sphereGeo, sphereMat)
sphereMesh.position.set(0, 5, 0)
scene.add(sphereMesh)
const sphereBody = new CANNON.Body({
mass: 1,
shape: new CANNON.Sphere(radius),
position: new CANNON.Vec3(0, 5, 0)
})
world.addBody(sphereBody)
// 🧩 碰撞事件监听
sphereBody.addEventListener('collide', (event) => {
console.log('🎯 碰撞发生!')
console.log('与谁发生碰撞:', event.body)
console.log('冲击速度:', event.contact.getImpactVelocityAlongNormal().toFixed(2))
})
// 动画更新
const clock = new THREE.Clock()
const timeStep = 1 / 60
function animate() {
requestAnimationFrame(animate)
const delta = clock.getDelta()
world.step(timeStep, delta)
sphereMesh.position.copy(sphereBody.position)
sphereMesh.quaternion.copy(sphereBody.quaternion)
controls.update()
renderer.render(scene, camera)
}
animate()
})
</script>
<template>
<canvas ref="canvasRef"></canvas>
</template>
三、碰撞信息可以做什么?
用途 | 描述 |
---|---|
播放音效 | 根据碰撞强度播放不同音效 |
触发逻辑 | 如“命中目标”后触发销毁或得分 |
记录日志 | 用于物理调试或分析仿真结果 |
可视化反应 | 冲击越强,颜色变化越剧烈 |
小技巧
- 若想检测多个刚体的碰撞,分别为它们绑定监听器。
- 想获取更详细的碰撞点信息,可查看
event.contact.ri
和event.contact.rj
(相对接触点)。