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!!