I wrote about the stack game in my previous post, and I covered it at almost every step

This is the previous implementation

You can play the game here

Which did not finish the invalid zone free fall, will be introduced in this article

The first step is to import the file

Ammmo.wasm.js and ammophysics.js ammmo.wasm.js are add-ons for physics. Ammmo.wasm.js and ammophysics.js

So you need to introduce both plug-ins into the project

<script src="./static/js/ammo.wasm.js"></script>
Copy the code
import { AmmoPhysics } from '.. /utils/AmmoPhysics.js';
Copy the code

AmmoPhysics returns a Promise object in the source code

init()

async function init() {
  physics = await AmmoPhysics();
  console.log(physics)
}
Copy the code

Printing out physics provides two methods, where addmesh adds the model you need to implement the object fall

Step 2: Add a baseboard

const floor = new THREE.Mesh(
  new THREE.BoxBufferGeometry(100.5.100),
  new THREE.MeshNormalMaterial({ color: 0x111111})); _this.scene.add(floor);Copy the code

Next, add the baseboard to Physics

physics.addMesh(floor);
Copy the code

The addMesh takes two parameters. The first parameter is the object to be applied, and the second parameter is an optional number. The default value is 0

AddMesh part code

function addMesh( mesh, mass = 0 ) {

    const shape = getShape( mesh.geometry );

    if( shape ! = =null ) {

        if ( mesh.isInstancedMesh ) {

            handleInstancedMesh( mesh, mass, shape );

        } else if( mesh.isMesh ) { handleMesh( mesh, mass, shape ); }}}Copy the code

Now set position.y of the baseboard to 100 and let the baseboard fall from height 100

floor.position.y = 100
physics.addMesh(floor, 1);
Copy the code

Now that we have achieved a free fall of an object, we will restore the floor and create two other free falls

const material = new THREE.MeshNormalMaterial();

const matrix = new THREE.Matrix4();

const geometryBox = new THREE.BoxBufferGeometry(5.5.5);
var boxes = new THREE.InstancedMesh(geometryBox, material, 2);
_this.scene.add(boxes);

for (let i = 0; i < boxes.count; i++) {

  matrix.setPosition(Math.random() - 10, (i + 1) * 10.Math.random() - (i * 4));
  boxes.setMatrixAt(i, matrix);
}

physics.addMesh(boxes, 1);
Copy the code

Create two instantiated meshes. The official website explains that instantiated meshes can improve rendering performance

You can use InstancedMesh to render a large number of objects with the same geometry and textures, but with different world transformations. Using InstancedMesh will help you reduce the number of draw calls, thereby improving your application’s overall rendering performance.

A small example of an object falling naturally looks like this, and then you need to add the free-falling object to the game

In the game, each object in the floorGroup will be set as no aftereffect object, and all invalid areas will be set as natural falling objects

Embed in the game

floor

Define physics when the game first creates a baseboard

Define an initAmmo method to assign to the ammammics method

Then add the base plate

async initAmmo() {
  this.physics = await AmmoPhysics();
  this.initFloor()
}
Copy the code

The method of creating the backplate is a little different from that before the transformation

initFloor() {
  // Define the physics plug-in
  // this.physics = await new AmmoPhysics();
  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);
  // Temporarily reduce the transparency of the floor by 0.5 to observe the object landing
  (this.floorCube.material as THREE.Material).transparent = true;
  (this.floorCube.material as THREE.Material).opacity = 0.5
  // Add the first baseboard to the physics plugin
  this.floorGroup.add(this.floorCube)
  this.floorGroup.updateMatrix()

  // Create an instantiated grid with the same location information as the backplane
  const floor = instancedMesh(this.floorCube)
  this.physics.addMesh(floor)
  console.log(this.physics)
  // Create a landable object
  const geometry = new THREE.BoxGeometry(5.5.5);
  const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
  const cube = new THREE.Mesh(geometry, material);
  cube.position.y = 80
  const box = instancedMesh(cube)
  this.floorGroup.add(box)
  // The object will move with the following attributes
  this.physics.addMesh(box, 1)}Copy the code

Create a method to instantiate the grid

// Create a physical grid
export function instancedMesh(box: any, position? :THREE.Vector3) {
  const size = new THREE.Vector3()
  getSize(box, size)
  const material = new THREE.MeshNormalMaterial();
  // Create an instantiated grid
  const geometryBox = new THREE.BoxBufferGeometry(size.x, size.y, size.z);
  var boxes = new THREE.InstancedMesh(geometryBox, material, 1);
  // Define a four-dimensional matrix to store the location information of objects
  const matrix = new THREE.Matrix4();
  // Pass the location information into the four-dimensional matrix
  if(position && position instanceof THREE.Vector3) {
    matrix.setPosition(position.clone())
  } else {
    matrix.setPosition(box.position.clone())
  }
  // Set the four-dimensional matrix to the new solid grid model
  boxes.setMatrixAt(0, matrix);
  return boxes
}
Copy the code

Take a look at the motion effects of the box you just created

Box as the natural falling object, floor as the floor object does not move, when the natural falling object collides with the floor object, physical collision effect will be carried out.

Just like in reality, drop a square from a position higher than the table, encounter the corner of the table, will carry out a series of physical movements such as collision, reversal, landing

The next step is to operate on the valid and invalid areas identified by the protagonist

Effective area

The effect of the active region is the same as that of the baseplate, neither of which moves, so the first step is to create an instantiated grid with the same information as the active region

// Clone a valid region
const newMesh:any = meshArr[0].clone();

// Temporary processing material is transparent
(newMesh.material as THREE.Material).transparent = true;
(newMesh.material as THREE.Material).opacity = 0.5

// Get the central point of the protagonist as the position of the valid area baseboard
const center = new THREE.Vector3()
getCenter(newMesh, center)

const phyMesh = instancedMesh(this.floorCube, center)
// The valid area is not moving, and the second parameter is not transmitted by default
this.physics.addMesh(phyMesh)
Copy the code

GetCenter is the encapsulated method for obtaining the element center, which the newly created instantiation grid will use as pISITION information

export function getCenter(mesh:THREE.Object3D, v3: THREE.Vector3) {
  if (v3 instanceofTHREE.Vector3) { getBox(mesh).getCenter(v3); }}Copy the code

Next, create a removable square to test the newly created instantiated grid

// Get the central point of the protagonist as the position of the valid area baseboard
const center = new THREE.Vector3()
getCenter(newMesh, center)
// console.log(center)

const phyMesh = instancedMesh(newMesh, center.clone())
// this.floorGroup.add(phyMesh)
// The valid area is not moving, and the second parameter is not transmitted by default
this.physics.addMesh(phyMesh,1)
// Create a test box
const geometry = new THREE.BoxGeometry(5.5.5);
const material = new THREE.MeshNormalMaterial();
const cube = new THREE.Mesh(geometry, material);
const newCenter = center.clone()
// Get the valid area size and place the test box at the edge of the valid area
const size = new THREE.Vector3()
getSize(newMesh, size)
newCenter.y = newCenter.y + 15
newCenter.x = newCenter.x + size.x/2
cube.position.copy(newCenter)
cube.updateMatrix ()

// Create an instantiated grid
const phyCube = instancedMesh(cube)
this.floorGroup.add(phyCube)
// Test the instantiated grid created by the test block as movable objects
this.physics.addMesh(phyCube, 1)
Copy the code

The test block hits the edge of the active zone, hits, rolls, lands, hits the bottom edge, hits, rolls, lands

So that’s what we’re going to do with the valid area, and then we’re going to do with the invalid area, as a free-falling object

Invalid area handling

The area outside the stack layer is considered invalid

// Determine the invalid area
if (meshArr[1]) {
  // Create invalid area entity grid
  const newMesh = meshArr[1]

  // Get the invalid region center point
  const center = new THREE.Vector3()
  getCenter(newMesh, center)

  // Create an invalid area materialized grid
  const phyMesh = instancedMesh(newMesh, center)

  this.invalidGroup.add(phyMesh)
  // Free fall
  this.physics.addMesh(phyMesh, 1)}Copy the code

The effect of one layer may not be visible, but better effect can be experienced if it is multi-layer

For multi-layer effects, giFs may be large and slow to load

The end of the

Well, the stack game can be declared over here, there may be some bugs or other problems, have time to slowly optimize it ~

Other steps have been written about in previous articles

The first step is basic initialization of the game

The second step is to control the protagonist to move and stop

The third step cutting and other functions

The fourth step to end the judgment, scoring device, etc

code

If you are interested, please feel free to post your scores in the comments section

A program without bugs is not a good program!!