学完粒子效果之后,我们来做一个实战:躲避汽车

在道路上随机生成一些汽车,人在道路中间,按键盘左右键来移动躲避汽车。
汽车和人的碰撞我们用包围盒 Box3 来检测。
碰撞的时候需要喷射献血,这个用粒子效果来做。
汽车的模型从 sketchfab 搜索:
https://sketchfab.com/3d-models/low-poly-cartoon-style-car-03-8c7f36b0a60745f487b300fa74d05990

https://sketchfab.com/3d-models/low-poly-cartoon-style-car-01-69461da2e3a842c0868f5187c1282674

人的模型也是:
https://sketchfab.com/3d-models/aaron-avatar-b99aa8c330f040649dbda4c082f6328b

创建项目:
npx create-vite dodge-cars

进入项目,安装依赖:
npm install
npm install --save three
npm install --save-dev @types/three
改下 src/main.js
import './style.css';
import * as THREE from 'three';
import {
OrbitControls
} from 'three/addons/controls/OrbitControls.js';
import mesh from './mesh.js';
const scene = new THREE.Scene();
scene.add(mesh);
const light = new THREE.DirectionalLight(0xffffff);
light.position.set(500, 300, 600);
scene.add(light);
const light2 = new THREE.AmbientLight();
scene.add(light2);
const axesHelper = new THREE.AxesHelper(1000);
scene.add(axesHelper);
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(60, width / height, 1, 10000);
camera.position.set(0, 500, 500);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height)
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
document.body.append(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
创建 Scene、Light、Camera、Renderer
改下 style.css
body {
margin: 0;
}
然后创建 mesh.js
import * as THREE from 'three';
const group = new THREE.Group();
const loader = new THREE.TextureLoader();
async function createRoad() {
const texture = loader.load('./road.png');
texture.colorSpace = THREE.SRGBColorSpace;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.y = 15;
const geometry = new THREE.PlaneGeometry(1000, 10000);
const material = new THREE.MeshLambertMaterial({
map: texture,
aoMap: texture
});
const road = new THREE.Mesh(geometry, material);
group.add(road);
road.rotateX(-Math.PI / 2);
}
createRoad();
export default group;
用 PlaneGeometry 画马路,旋转一下。
贴上公路的纹理图片,在竖直方向重复 10 次。
road.png 是这张图片:


这张图片是网上搜的,截取一部分,竖直方向重复就行:

跑起来看下:
npm run dev


然后把刚才那三个模型下载下来放到 public 目录下:
下载 glb 格式:


https://sketchfab.com/3d-models/aaron-avatar-b99aa8c330f040649dbda4c082f6328b#download


加载下:

const gltfLoader = new GLTFLoader();
async function createCars() {
const blueCarGltf = await gltfLoader.loadAsync('./blue-car.glb');
group.add(blueCarGltf.scene);
console.log(blueCarGltf);
blueCarGltf.scene.scale.setScalar(100);
}
createRoad();
createCars();

同样加载下另外两个模型:

const gltfLoader = new GLTFLoader();
async function createCars() {
const blueCarGltf = await gltfLoader.loadAsync('./blue-car.glb');
group.add(blueCarGltf.scene);
// console.log(blueCarGltf);
blueCarGltf.scene.scale.setScalar(150);
const orangeCarGltf = await gltfLoader.loadAsync('./orange-car.glb');
group.add(orangeCarGltf.scene);
// console.log(orangeCarGltf);
orangeCarGltf.scene.scale.setScalar(130);
orangeCarGltf.scene.position.x = 200;
}
async function createMan() {
const manGltf = await gltfLoader.loadAsync('./man.glb');
group.add(manGltf.scene);
console.log(manGltf);
manGltf.scene.scale.setScalar(90);
manGltf.scene.position.z = 200;
}
createRoad();
createCars();
createMan();
去掉 axesHelper,看下效果:

没啥问题。
案例代码上传了小册仓库
总结
这节我们开始写躲避汽车的实战。
我们用 PlaneGeometry 创建了公路,然后加载了从 sketchfab 找的车和任务模型。
下节让汽车和人动起来。