Skip to content

144. 物理引擎 cannon:小球发射(三)

Published:

上节定义了物理世界,实现了给小球一个推力,让它滚动撞击立方体:

2025-11-16 17.25.51.gif

这节我们优化下效果,然后加上发射多个小球的功能。

首先把地面加大,然后重力加速度调大一点:

image.png

盒子质量加大一点:

image.png

2025-11-16 17.46.41.gif

效果好多了,但是球和盒子滚动太久,我们把他们和地面的摩擦力加大一下:

image.png

加大摩擦力,再给球和盒子一个碰撞的弹力。

2025-11-16 17.50.40.gif

没有阴影显得不够真实,我们加一下阴影:

image.png

renderer.shadowMap.enabled = true;

image.png

directionLight.castShadow = true;
directionLight.shadow.mapSize.set(2048, 2048);
directionLight.shadow.camera.near = 1;
directionLight.shadow.camera.far = 5000;
directionLight.shadow.camera.left = -3000;
directionLight.shadow.camera.right = 3000;
directionLight.shadow.camera.top = 3000;
directionLight.shadow.camera.bottom = -3000;

开启 renderer 和平行光的阴影,设置下投影相机的范围。

然后给物体开始接收和投射阴影:

image.png

image.png

mesh.castShadow = true;

image.png

plane.receiveShadow = true;

2025-11-16 17.58.26.gif

最后实现点击的发射小球的功能:

image.png

const raycaster = new THREE.Raycaster();
const mousePos = new THREE.Vector2();
const shootPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
window.addEventListener('click', (event) => {
    mousePos.x = (event.clientX / window.innerWidth) * 2 - 1;
    mousePos.y = -(event.clientY / window.innerHeight) * 2 + 1;

    raycaster.setFromCamera(mousePos, camera);

    const hit = new THREE.Vector3();
    if (raycaster.ray.intersectPlane(shootPlane, hit)) {
        shootBallAt(hit.x, 1, hit.z);
    }
});

监听点击事件,基于点击位置和 camera 方向生成一条射线,和平面判断相交,这样就知道在哪里生成小球了。

小球离地一点距离,生成的时候会给他施加推力。

我们在 main.js 导出 camera:

image.png

试一下:

2025-11-16 18.09.20.gif

这样就实现了发射小球的功能。

案例代码上传了小册仓库

总结

这节我们调整了下地面的摩擦力,重力加速度、小球和盒子的弹力等,优化了整体效果。

然后添加了阴影。

最后我们实现了点击计算出平面的位置,然后在那个位置发射小球的功能。

虽然我们发射的是小球,但发射子弹之类的也是一样的原理。

评论