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

这节我们优化下效果,然后加上发射多个小球的功能。
首先把地面加大,然后重力加速度调大一点:

盒子质量加大一点:


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

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

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

renderer.shadowMap.enabled = true;

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 和平行光的阴影,设置下投影相机的范围。
然后给物体开始接收和投射阴影:


mesh.castShadow = true;

plane.receiveShadow = true;

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

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:

试一下:

这样就实现了发射小球的功能。
案例代码上传了小册仓库
总结
这节我们调整了下地面的摩擦力,重力加速度、小球和盒子的弹力等,优化了整体效果。
然后添加了阴影。
最后我们实现了点击计算出平面的位置,然后在那个位置发射小球的功能。
虽然我们发射的是小球,但发射子弹之类的也是一样的原理。