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