Threejs系列--18游戏开发--沙漠赛车游戏【loading资源加载进度条】
序言
本章将实现loading加载资源进度条。
目录结构
资源目录里面的结构不变,点击传送门快速查看。
|__src
|__assets
|__js
| |__base 基础类文件夹
| |__Camera.js 相机类
| |__Resources.js 资源类
| |__geometries 定制的物体类文件夹
| |__AreaFloorBorderBufferGeometry.js 进度条几何体 【新增】
| |__materials 材质类文件夹
| |__Floor.js 地面材质
| |__AreaFloorBorder.js 进度条着色器 【新增】
| |__passes 合成器通道文件夹
| |__Blur.js 模糊着色器
| |__Glows.js 发光着色器
| |__utils 工具类文件夹
| |__Sizes.js 画布大小控制类
| |__EventEmitter.js 基础事件处理器
| |__Time.js 动画刷新
| |__Loader.js 加载器
| |__world 精灵类文件夹
| |__Area.js 区域基础类 【新增--基础实现】
| |__Areas.js 区域管理类 【新增--管理各个区域】
| |__index.js 精灵类 【新增--进度条导入与切换】
| |__Floor.js 地面类
| |__Application.js 初始化游戏的文件
|__index.js 入口
|__index.css 小项目,样式一丢丢
代码一览
AreaFloorBorderBufferGeometry.js代码
import * as THREE from "three";
/**
* 自定义进度条几何体
*/
class AreaFloorBorderBufferGeometry {
constructor(_width, _height, _thickness) {
this.parameters = {
width: _width,
height: _height,
thickness: _thickness,
};
this.type = "AreaFloorBufferGeometry";
const length = 8;
const vertices = new Float32Array(length * 3);
const indices = new Uint32Array(length * 6);
const outerWidth = _width;
const outerHeight = _height;
const innerWidth = outerWidth - _thickness;
const innerHeight = outerHeight - _thickness;
// Vertices
vertices[0 * 3 + 0] = innerWidth * 0.5;
vertices[0 * 3 + 1] = innerHeight * 0.5;
vertices[0 * 3 + 2] = 0;
vertices[1 * 3 + 0] = innerWidth * 0.5;
vertices[1 * 3 + 1] = -innerHeight * 0.5;
vertices[1 * 3 + 2] = 0;
vertices[2 * 3 + 0] = -innerWidth * 0.5;
vertices[2 * 3 + 1] = -innerHeight * 0.5;
vertices[2 * 3 + 2] = 0;
vertices[3 * 3 + 0] = -innerWidth * 0.5;
vertices[3 * 3 + 1] = innerHeight * 0.5;
vertices[3 * 3 + 2] = 0;
vertices[4 * 3 + 0] = outerWidth * 0.5;
vertices[4 * 3 + 1] = outerHeight * 0.5;
vertices[4 * 3 + 2] = 0;
vertices[5 * 3 + 0] = outerWidth * 0.5;
vertices[5 * 3 + 1] = -outerHeight * 0.5;
vertices[5 * 3 + 2] = 0;
vertices[6 * 3 + 0] = -outerWidth * 0.5;
vertices[6 * 3 + 1] = -outerHeight * 0.5;
vertices[6 * 3 + 2] = 0;
vertices[7 * 3 + 0] = -outerWidth * 0.5;
vertices[7 * 3 + 1] = outerHeight * 0.5;
vertices[7 * 3 + 2] = 0;
// Index
indices[0 * 3 + 0] = 4;
indices[0 * 3 + 1] = 0;
indices[0 * 3 + 2] = 1;
indices[1 * 3 + 0] = 1;
indices[1 * 3 + 1] = 5;
indices[1 * 3 + 2] = 4;
indices[2 * 3 + 0] = 5;
indices[2 * 3 + 1] = 1;
indices[2 * 3 + 2] = 2;
indices[3 * 3 + 0] = 2;
indices[3 * 3 + 1] = 6;
indices[3 * 3 + 2] = 5;
indices[4 * 3 + 0] = 6;
indices[4 * 3 + 1] = 2;
indices[4 * 3 + 2] = 3;
indices[5 * 3 + 0] = 3;
indices[5 * 3 + 1] = 7;
indices[5 * 3 + 2] = 6;
indices[6 * 3 + 0] = 7;
indices[6 * 3 + 1] = 3;
indices[6 * 3 + 2] = 0;
indices[7 * 3 + 0] = 0;
indices[7 * 3 + 1] = 4;
indices[7 * 3 + 2] = 7;
const geometry = new THREE.BufferGeometry();
geometry.setIndex(new THREE.BufferAttribute(indices, 1, false));
geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(vertices, 3)
);
return geometry;
}
}
export default AreaFloorBorderBufferGeometry;
AreaFloorBorder.js代码
import * as THREE from "three";
import shaderFragment from "../../assets/shaders/areaFloorBorder/fragment.glsl";
import shaderVertex from "../../assets/shaders/areaFloorBorder/vertex.glsl";
/**
* 进度条着色器
*/
export default function () {
const uniforms = {
uColor: { value: null },
uAlpha: { value: null },
uLoadProgress: { value: null },
uProgress: { value: null },
};
const material = new THREE.ShaderMaterial({
wireframe: false,
transparent: true,
depthTest: true,
depthWrite: false,
uniforms,
vertexShader: shaderVertex,
fragmentShader: shaderFragment,
});
return material;
}
Area.js代码
import * as THREE from 'three';
import EventEmitter from "../utils/EventEmitter";
import AreaFloorBorderBufferGeometry from '../geometries/AreaFloorBorderBufferGeometry';
import AreaFloorBorderMaterial from '../materials/AreaFloorBorder';
/**
* 区域类
*/
export default class Area extends EventEmitter{
constructor(_options){
super();
this.position = _options.position;
this.halfExtents = _options.halfExtents;
this.container = new THREE.Object3D();
this.container.position.x = this.position.x;
this.container.position.y = this.position.y;
this.container.matrixAutoUpdate = false;
this.container.updateMatrix();
this.setFloorBorder();
}
setFloorBorder(){
this.floorBorder = {};
//创建进度条
this.floorBorder.geometry = new AreaFloorBorderBufferGeometry(
this.halfExtents.x * 2,
this.halfExtents.y * 2,
0.25
);
this.floorBorder.material = new AreaFloorBorderMaterial();
this.floorBorder.material.uniforms.uColor.value = new THREE.Color(0xffffff);
this.floorBorder.material.uniforms.uAlpha.value = 1;
this.floorBorder.material.uniforms.uLoadProgress.value = 1;
this.floorBorder.material.uniforms.uProgress.value = 1;
this.floorBorder.mesh = new THREE.Mesh(this.floorBorder.geometry, this.floorBorder.material);
console.log(this.floorBorder.geometry)
this.floorBorder.mesh.matrixAutoUpdate = false;
this.container.add(this.floorBorder.mesh);
}
}
Areas.js代码
import * as THREE from 'three';
import Area from "./Area";
/**
* 区域管理
*/
export default class Areas {
constructor(_options) {
this.resources = _options.resources;
this.container = new THREE.Object3D();
this.container.matrixAutoUpdate = false;
}
add(_options) {
const area = new Area({
resources: this.resources,
..._options,
});
this.container.add(area.container);
return area;
}
}
index.js代码
import * as THREE from "three";
import gsap from "gsap";
import Floor from "./Floor.js";
import Areas from "./Areas.js";
export default class {
constructor(_options){
...
//设置世界中的区域加载
this.setAreas();
//设置启动屏
this.setStartingScreen();
}
setStartingScreen() {
this.startingScreen = {};
this.startingScreen.area = this.areas.add({
position: new THREE.Vector2(0, 0),
halfExtents: new THREE.Vector2(2.35, 1.5),
});
...
this.resources.on('progress', _progress => {
this.startingScreen.area.floorBorder.material.uniforms.uAlpha.value = 1;
this.startingScreen.area.floorBorder.material.uniforms.uLoadProgress.value = _progress;
})
this.resources.on('ready', () => {
window.requestAnimationFrame(() => {
gsap.to(this.startingScreen.area.floorBorder.material.uniforms.uAlpha, {duration: 0.3, value: 0.3 });
...
})
})
}
...
setAreas(){
this.areas = new Areas({
resources: this.resources
})
this.container.add(this.areas.container)
}
}
代码解读
AreaFloorBorderBufferGeometry.js自定义了需要的进度条
AreaFloorBorder.js使用自定义的着色器渲染材质
Area.js合成自定义的进度条
Areas.js统一管理区块【进度条也是一个区块】
index.js导入Areas,使用进度条,根据资源加载进度,控制参数变化