preface
Recently I have been working on my knowledge of three.js, and I think wechat mini games are a good trial and error field. To a 2048 small game tread pit.
Let’s start with a scene diagram
At first glance, it looks like 2D. It has nothing to do with three.js. Look closely, there are shadows, there are transparency, there are dimensions, everything is in detail, 3D, yes.
Scan the code for early access
Here is a joke, wechat part of the version, into the game part of the model may flash back, the specific reason is unknown.
Three development preconditions
- This running environment is wechat mini game. If the browser environment, with Google must be right, specific compatibility, please check
https://caniuse.com
. - Assuming you have some level of JavaScript, some knowledge of 3D graphics is preferred.
The basic concept
- Scene: Provide a space with three – dimensional coordinate axes
- Camera: equivalent to the human eye, is the perspective. There are two kinds of cameras, orthographic cameras
OrthographicCamera
And perspective projection camerasPerspectiveCamera
. Different projection methods are required for 3d scenes of different applications. For example, orthographic projection (parallel projection) is often used in planar fields, while perspective projection (central projection) is often used in game scenes. - Threejs virtual light source is a simulation of natural light. Light source: ambient light (
AmbientLight
), parallel light (DirectionalLight
), hemispherical light (HemisphereLight
), point light source (PointLight
), planar light source (RectAreaLight
), spotlight (SpotLight
), etc. - Geometry: Geometry of a model, such as a cube, cylinder, or custom geometry. Three. Js encapsulates some geometric model cubic geometry (
BoxGeometry
), cylindrical geometry (CylinderGeometry
) etc. - Material: The appearance of geometry. Three.js encapsulates some materials, such as shiny surfaces with specular highlights (
MeshPhongMaterial
), mesh material without specular highlights (MeshLambertMaterial
), etc. - Texture: A map of the surface of the material. It can be an image or a map
canvas
The graph that was drawn - A renderer is a combination of scene camera lighting and model rendering in some way
Trust the concept above, it’s enough.
Scenario instance
- First,
new
The scene, here I amnew
Two scenes, the game interface needs a three-dimensional sense, using a center projection, the rest of the score and other objects, need to tile on the interface, using parallel projection. Add auxiliary lines, lights and background colors to the center projection scene.
createScene() {
this.scene = new THREE.Scene();
this.hudScene = new THREE.Scene();
const axesHelper = new THREE.AxesHelper(1000);
const lights = this.createLight();
Object.keys(lights).forEach((value) = > {
this.scene.add(lights[value]);
});
this.scene.add(axesHelper);
this.scene.background = new THREE.Color(0x3498db);
}
Copy the code
- again
new
There are two cameras, one orthographic camera and one perspective camera. Set orientation, camera position, and focus position.
createCamera() {
this.camera = new THREE.PerspectiveCamera(
45,
screenWidth / screenHeight,
0.1.5000
);
this.camera.up.set(0.1.0);
this.camera.position.set(0.0.2000);
this.camera.lookAt(this.scene.position);
}
createHudCamera() {
this.hudCamera = new THREE.OrthographicCamera(
-screenWidth / 2,
screenWidth / 2,
screenHeight / 2,
-screenHeight / 2.- 1000..1000
);
this.hudCamera.up.set(0.1.0);
this.hudCamera.position.set(0.0.1000);
this.hudCamera.lookAt(new THREE.Vector3(0.0.0));
}
Copy the code
new
Light source, here set ambient light and parallel light, where parallel light can set shadow.
createLight() {
const directionalLight = new THREE.DirectionalLight(0xffffff.0.3);
directionalLight.position.set(400.100.500);
directionalLight.castShadow = true;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 1000;
directionalLight.shadow.camera.left = - 500.;
directionalLight.shadow.camera.right = 500;
directionalLight.shadow.camera.top = 500;
directionalLight.shadow.camera.bottom = - 500.;
directionalLight.shadow.mapSize.width = 3024;
directionalLight.shadow.mapSize.height = 3024;
return {
ambientLight: new THREE.AmbientLight(0xffffff.0.7),
directionalLight,
};
}
Copy the code
new
The renderer
createRenderer() {
let { devicePixelRatio, innerWidth, innerHeight } = window;
this.renderer = new THREE.WebGLRenderer({
canvas,
antialias: true.precision: "highp"});this.renderer.setClearColor(0xffffff.1);
this.renderer.setPixelRatio(devicePixelRatio);
this.renderer.setSize(innerWidth, innerHeight);
this.renderer.shadowMap.enabled = true;
this.renderer.autoClear = false;
}
Copy the code
- Apply colours to a drawing
animate() {
this.renderer.render(this.scene, this.camera);
this.renderer.render(this.hudScene, this.hudCamera);
requestAnimationFrame((a)= > {
this.animate();
});
}
Copy the code
Create the model, where the texture is drawn on canvas,
// Create the plane model here
createPlane() {
const geometry = new THREE.PlaneGeometry(width, length);
const material = new THREE.MeshPhongMaterial({
color: 0xdddddd.specular: 0xdddddd.map: this.texture(),
});
this.instance = new THREE.Mesh(geometry, material);
this.instance.name = "plane";
// Set the shadow
this.instance.castShadow = true;
this.instance.receiveShadow = true;
}
// Create a texture
texture() {
let w = width;
const canvas = wx.createCanvas();
canvas.width = canvas.height = w;
const context = canvas.getContext("2d"); . let map =new THREE.CanvasTexture(canvas);
map.minFilter = THREE.LinearFilter;
return map;
}
Copy the code
Add event
- Click event, place the object to which you want to add the click event in one
group
When the user clicks on the screen,threejs
provideRaycaster
For example, a “laser” is fired from the touch point, and all objects swept by the laser are recorded in the returned array.
getEventObject(event, camera = null, group = []) {
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / screenWidth) * 2 - 1;
mouse.y = -(event.clientY / screenHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(group, true);
return intersects;
}
Copy the code
- Sliding events are provided via wechat
onTouchStart
和onTouchEnd
, obtain the starting and ending coordinate points, and then judge the sliding direction by the sliding distance and Angle.
fn(callback) {
if (this.endId === this.startId) {
let w = this.xt - this.x0;
let h = this.yt - this.y0;
let k = h / w;
if (k > 2 || k < 2 -) {
if (h < - 20) callback(0); / * * / up
if (h > 20) callback(1); / * * / down
}
if (k < 0.5 && k > 0.5) {
if (w < - 20) callback(2); / * * / to the left
if (w > 20) callback(3); / * * / to the right}}}Copy the code
Optimize performance
- Geometry, materials, textures, etc. should be shared as much as possible. Consider using memory functions
- Called in time to remove the model
dispose()
, including geometry, materials and textures
conclusion
Construct a small game scene through three. js, the process is relatively simple, about four steps.
- Create a scene, set up the lights, set up the camera position
- The combination of geometric shapes and materials creates different models
- Render the model in the scene. A 3D interface comes out
- Add events and adjust scenarios based on business requirements
Experience and code