Application Stack
webpack
threejs
typescript
Step 1, preparation (think about gameplay, draw a mind map, build a project, create a scene)
File directory
Json │ package.json │ readme. md │ tsconfig.json │ webpack.config.js │ stackdump │ package. lock.json │ package Webpack. Plugins. Js │ └ ─ SRC ├ ─ HTML │ index. The HTML / / HTML │ └ ─ screen index. The ts / / ts entry documentsCopy the code
Below are the main features and the selection of scene elements
From the composition of the soul painter
Start by creating the scene and other necessary elements
A pile of code
const THREE = require("three");
import { OrbitControls } from ".. /.. /node_modules/three/examples/jsm/controls/OrbitControls";
class CreateScene {
// Screen width
width: number = window.innerWidth;
// Screen height
height: number = window.innerHeight;
/ / 3 d container
container: any = document.body;
frustumSize = 2000;
scene / / the scene
renderer / / the renderer
camera / / camera
controls / / controller
constructor() {
this.createScene()
this.createCamera()
this.createRenderer()
this.createControls()
this.render()
this.axesHelper(100)
this.createBackground()
// Listen for screen size changes
window.addEventListener("resize".this.onWindowResized.bind(this), false);
}
// Create a scene
createScene(): void {
this.scene = new THREE.Scene();
}
// Create renderer
createRenderer(): void {
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize(this.width, this.height);
document.body.appendChild(this.renderer.domElement);
}
// Create camera
createCamera(): void {
this.camera = new THREE.OrthographicCamera(this.width / - 2.this.width / 2.this.height / 2.this.height / - 2.1.this.frustumSize);
this.camera.zoom = 3
console.log(this.camera)
this.camera.position.set(200.250.200)
this.scene.add(this.camera);
this.camera.updateProjectionMatrix()
}
// Create a controller
createControls(): void {
this.controls = new OrbitControls(
this.camera,
this.renderer.domElement
);
this.controls.screenSpacePanning = true
this.controls.target = new THREE.Vector3(0.100.0)}// Render the animation
animate(): void {
requestAnimationFrame(this.render.bind(this));
}
/ / rendering
render(): void {
this.animate()
this.renderer.render(this.scene, this.camera);
this.controls.update();
}
// Create an axis helper line
axesHelper(len: number) :void {
const axesHelper = new THREE.AxesHelper(len);
this.scene.add(axesHelper);
}
// Listen for screen changes
onWindowResized() {
this.camera.left = this.width / - 2;
this.camera.right = this.width / 2;
this.camera.top = this.height / 2;
this.camera.bottom = this.height / - 2;
this.camera.updateProjectionMatrix();
this.width = window.innerWidth
this.height = window.innerHeight
this.renderer.setSize(this.width, this.height);
}
// Create sky background
createBackground(): any {
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 32;
const context = canvas.getContext('2d');
const gradient = context.createLinearGradient(0.0.0.32);
gradient.addColorStop(0.0.'#014a84');
gradient.addColorStop(0.5.'#0561a0');
gradient.addColorStop(1.0.'#437ab6');
context.fillStyle = gradient;
context.fillRect(0.0.1.32);
const sky = new THREE.Mesh(
new THREE.SphereBufferGeometry(1000),
new THREE.MeshBasicMaterial({ map: new THREE.CanvasTexture(canvas), side: THREE.BackSide })
);
this.scene.add(sky); }}export { CreateScene, THREE }
Copy the code
It is then referenced and instantiated directly in the screen/index.ts entry file
import {CreateScene,THREE} from '.. /createScene/index'
const _this = new CreateScene()
Copy the code
The creation scenario is as follows
The second step is to create the base and the first moving hero
Create a leading role
initFloor() {
const w: number = 30
const h: number = 50
const l: number = 30
const floorParams = {
w: w,
h: h,
l: l,
x: w / 2.y: h / 2.z: l / 2
}
this.floorCube = createCube(floorParams)
this.floorGroup.add(this.floorCube)
}
Copy the code
CreateCube is a wrapper method that creates blocks, including backboards and protagonists
// The parameters needed to create the block
interface cubeParams {
w: number // Width corresponds to the X-axis
h: number // The height corresponds to the Y-axis
l: number The length corresponds to the z-axis
x: number // the X-axis position
y: number // Y position
z: number // The z-axis position
}
// Create a block
export function createCube(p: cubeParams) :any {
const geometry = new THREE.BoxGeometry(p.w, p.h, p.l);
const material = new THREE.MeshNormalMaterial();
const cube = new THREE.Mesh(geometry, material);
cube.position.set(p.x, p.y, p.z)
return cube
}
Copy the code
After creation
Next you need to create the protagonist (movable block)
The information to be obtained is the height of the baseboard, the vertex information of the baseboard and the position information of the baseboard. In the past, the protagonists will be regarded as the content of the baseboard.
So instead of adding the backplane directly to the scene, create a group
Size can be obtained using the wrapped getBox method
The wrapped getBox method
const THREE = require("three"); function getBox(mesh: any) { let b = new THREE.Box3(); b.expandByObject(mesh); Vector3 export function getSize(mesh: any, v3:any) {getBox(mesh).getsize (v3); Export function getPosition(mesh:any, v3: any) {mesh. GetWorldPosition (v3)}Copy the code
Create the protagonist and set the location information
createlead() {
const size = new THREE.Vector3()
const mesh = this.floorGroup
// Get the size
getSize(mesh, size)
const position = new THREE.Vector3()
// The position of the backplane should be 0 by default
getPosition(mesh, position)
const gy = position.y // The Y value of the backplane
const y = size.y + gy + this.leadY / 2 // The main character's Y value
// Set the odd-th hero to come from the negative side of the z axis, and the even-th hero to come from the X axis
// You need a hero counter, which can also be used to count scores
// The starting point is 30 away from the base plate
// The initial position of the main character
const flag = this.leadCount % 2= = =0 // Is it even
// start point of x
let sx = (flag ? -this.startPoint : 0) + this.size / 2
// z start point
let sz = (flag ? 0 : -this.startPoint) + this.size / 2
// Create a protagonist
const leadParam = {
w: this.size,
h: this.leadY,
l: this.size,
x: sx,
y: y,
z: sz
}
const leadCube = createCube(leadParam)
this.scene.add(leadCube)
// After creating a role, the counter increases by 1
this.leadCount++
}
Copy the code
A few more calls will create the protagonist from both sides
Here is initGame code and a bunch of code sweat!!
const THREE = require("three"); import { createCube } from '.. /utils/tools' import { getSize, getPosition } from '.. /utils/getBox' class CreateGame {scene: any floorCube: any floorGroup: any LeadY: number = 5 // leadY: number = 0 // counter startPoint: LeadInterval: any = null // Constructor (element: constructor) any) { this.scene = element.scene this.floorGroup = new THREE.Group() this.scene.add(this.floorGroup) this.initFloor() } initFloor() { const w: number = this.size const h: number = 50 const l: number = this.size const floorParams = { w: w, h: h, l: l, x: w / 2, y: h / 2, z: l / 2 } this.floorCube = createCube(floorParams) this.floorGroup.add(this.floorCube) this.floorGroup.updateMatrix() } Createlead () {const size = new three.vector3 () const mesh = this.floorGroup Size) const position = new three.vector3 () Position) const gy = position.y const y = size.y + gy + this.leadY / 2 The even-numbered hero comes from the X-axis // needs a hero counter, LeadCount % 2 === 0 const flag: Boolean = this.leadCount % 2 === 0 (flag ? -this.startPoint: 0) + this.size / 2 // z let sz:number = (flag? 0: -this.startPoint) + this.size / 2 // Create a lead const leadParam = {w: this.size, h: this.leady, l: this.size, x: sx, y: y, z: Sz} const leadCube = createCube(leadParam) this.floorgroup. add(leadCube) this.leadCount++}} export { CreateGame }Copy the code
The game is divided into four steps to write an essay
The first step is basic initialization of the game
The second step is to control the protagonist to move and stop
In the third step, the protagonist is cut into the inner square of the base plate, and the outer square of the base plate is free falling
Step 4: Scoring device, loading medium other functions