本文借鉴了The Aviator的玩法和部分代码,最终效果如下。
1 加载模型和动画
参考学习笔记1中的方法,将海豚和鲨鱼模型及动画加载到three.js中。
// 对象构造器
let playerObj;
const mixers = [];
// 游戏人物
const Player = function () {
const isExist = playerObj ? true : false;
const loader = new THREE.FBXLoader();
loader.load('assets/models/Player' + OPTIONS.player + '.fbx', function (object) {
object.mixer = new THREE.AnimationMixer(object);
mixers.push(object.mixer);
const action = object.mixer.clipAction(object.animations[0]);
action.play();
// 侧面面对镜头
object.rotation.y = 1.57;
object.position.y = 50;
object.position.z = 0;
const scale = OPTIONS.objScale[OPTIONS.player];
object.scale.set(scale, scale, scale);
// 加入场景
if (isExist) {
scene.remove(playerObj)
playerObj = object;
scene.add(object);
} else {
playerObj = object;
scene.add(object);
// 载入obj后开始第一次动画循环
loop();
}
});
};
因为游戏开始时需要选择使用两个游戏人物中的哪一个,所以isExist用于判断之前是否已载入某个模型。变量scale判断载入的是哪个模型并调节模型大小。载入完毕后开始动画循环。
2 加入海底滚筒
海底加入滚筒并不断向后滚动,模拟主角游动的场景。
// 海底
const Sea = function () {
// 锥:上底半径,下底半径,高度,圆面划分,高度划分
const geom = new THREE.CylinderGeometry(OPTIONS.seaRadius, OPTIONS.seaRadius, 200, 40, 10);
// 滚动
geom.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI/2));
geom.mergeVertices();
// 增加波动
this.waves = [];
for (let i=0; i < geom.vertices.length; i++) {
this.waves.push({
y: geom.vertices[i].y,
x: geom.vertices[i].x,
z: geom.vertices[i].z,
ang: Math.random() * Math.PI * 2,
amp: 5 + Math.random() * 15,
speed: 0.016 + Math.random() * 0.032
});
};
// 材质
const mat = new THREE.MeshPhongMaterial({
color: COLORS.sand
});
mat.flatShading = true;
this.mesh = new THREE.Mesh(geom, mat);
this.mesh.position.y = -600;
this.mesh.position.z = -100;
scene.add(this.mesh);
}
Sea.prototype.wave = function () {
const verts = this.mesh.geometry.vertices;
for (let i=0; i < verts.length; i++) {
const vprops = this.waves[i];
verts[i].x = vprops.x + Math.cos(vprops.ang) * vprops.amp;
verts[i].y = vprops.y + Math.sin(vprops.ang) * vprops.amp;
vprops.ang += vprops.speed;
}
this.mesh.geometry.verticesNeedUpdate = true;
sea.mesh.rotation.z += 0.005;
}
3 引入绿色小球
绿色小球触碰后消失,并增加得分。绿球起始在Math.PI / 3位置处生成,当全部被主角吃掉或运动至-Math.PI / 3处时,上一组绿色小球消失,并重新生成下一组。对每个绿色小球,每一帧除自转公转外,还需判断是否与主角碰撞。若发生碰撞,绿色小球消失,启动爆炸的粒子效果并增加得分。
// 绿色小球
const GreenBalls = function () {
this.generate();
}
GreenBalls.protot