Warehouse address: github.com/haiyoucuv/W…

Introduction concept: collision box collision

In the last section, we finished optimizing the barrier creation and improved the performance significantly

This section will complete the determination of death conditions. The collision detection method in this case contains some strong references and is not suitable for the development of large projects

  • 1. Falling to the ground and dying

  • 2. Death from hitting an obstacle

  • 3. Death pauses the game

Fall to the ground dead

First, modify the Bird class and add a dieLine parameter, indicating the death line. If our player touches this line, it will be declared dead

class Bird extends Sprite {
	/ *... * /
	dieLine; / / death
	/ *... * /
}
Copy the code

Modify the Ready in FlppyStage to set the bird’s death line after all nodes have addChild

Due to DOM restrictions, properties such as clientWidth cannot be obtained when the node is not in rendering, so set the bird’s death line only after all nodes have addChild

Since the ground is placed at the bottom of landMgr and the size of landMgr is the same as the body, land and Bird are in the same space

Get death height winsize.height-land1.size.height

class FlppyBird extends GameStage {

	/ *... * /

	async ready() {
		/ *... * /

		/ / death
		bird.dieLine = winSize.height - land1.size.height;

		/ *... * /
	}

	/ *... * /

}
Copy the code

Modify the Bird update function

  • Hit the death line and stay at the death line
  • printIt crashed. You're dead

Because the anchor is in the upper left corner, you should subtract your height from dieLine when calculating whether you are dead

class Bird extends Sprite {

	/ *... * /

	dieLine; / / death

	/ *... * /

	update() {
		super.update();

		// v is equal to v0 plus a times t squared
		this.speed += this.gravity; // Velocity = velocity + acceleration * time ²

		let top = this.top + this.speed;  // Update the location

		// dieLine should subtract its height because the anchor is in the upper left corner
		const dieLine = this.dieLine - this.size.height;

		// Stop at dieLine if it is greater than dieLine
		if (top > dieLine) {
			top = dieLine;
			console.log("It crashed. You're dead.");
		}

		this.top = top; }}Copy the code

Run the code and the bird will land on the ground and the console will print crash and you are dead

Box collision

A box collision is a collision that uses the bounding box of the gameobject to detect whether there is an intersection

Map the box to the X-axis and Y-axis to get the line segments A1->A2, B1->B2, A3->A4, B3->B4

If A1->A2 and B1->B2 have an intersection, and A3->A4 and B3->B4 also have an intersection, then two boxes can be deemed to intersect, namely, two objects collide

As shown in the figure, no intersection is determined as no collision

As shown in the figure, only one axis of the map has an intersection is judged to be collision free

The intersection of the mappings on both axes in the figure is considered a collision

Code implementation

/** * Box collision *@param rect1 {top, left, size:{width, height}}
 * @param rect2 {top, left, size:{width, height}}
 * @returns {boolean}* /
function boxCollisionTest(rect1, rect2) {
	const { top: t1, left: l1 } = rect1;
	const { width: w1, height: h1 } = rect1.size;

	const { top: t2, left: l2 } = rect2;
	const { width: w2, height: h2 } = rect2.size;

	const b1 = t1 + h1,
		b2 = t2 + h2,
		r1 = l1 + w1,
		r2 = l2 + w2;

	return ((t1 > t2 && t1 < b2) || (t2 > t1 && t2 < b1))  // Check the intersection of t1->b1 and T2 ->b2
		&& ((l1 > l2 && l1 < r2) || (l2 > l1 && l2 < r1));   // Check the intersection of L1 ->r1 and L2 -> R2
}
Copy the code

transformPieMgr

  • Pass to our main characterbird
  • In the mobilepieAnd then check for collisions
/** * PieMgr */
class PieMgr extends GameObject {

	/ *... * /

	bird;   / / player

	/ *... * /

	update() {
		super.update();

		// All pies are shifted to the left simultaneously
		const { speed, pieArr } = this;
		pieArr.forEach((pie) = > {
			/ / move
			pie.left -= speed;
			if (pie.left <= -pie.size.width) {  // If you remove the screen
				this.pieArr.splice(this.pieArr.indexOf(pie), 1);    // Remove from the managed list
				this.removeChild(pie);                              // Remove the child node
				ObjectPool.put("pie", pie);                         // Add to the object pool
				return;
			}

			// Check for collisions
			Up and pie. Down are relative to pie, so reconstruct the left and top of the square
			const pieUpBox = {
				left: pie.left,
				top: pie.top + pie.up.top,
				size: pie.up.size,
			}

			const pieDownBox = {
				left: pie.left,
				top: pie.top + pie.down.top,
				size: pie.down.size,
			}
			if (boxCollisionTest(this.bird, pieUpBox) || boxCollisionTest(this.bird, pieDownBox)) {
				console.log("Hit a barrier, you're dead."); }}); }}const pieMgr = this.pieMgr = new PieMgr(4.1000, bird);
Copy the code

Run the case to get results

Death pause game

In this case, we can simply think of pausing the game as pausing the loop

  • In FlppyBirdupdateInsert control variables intopause
  • ifpauseIf true, it is not executedsuper.update
class FlppyBird extends GameStage {

	pause = false;

	/ *... * /

	update() {
		if (this.pause) return;
		super.update(); }}Copy the code

Use events to notify the game to pause

This case does not take you to implement their own event transceiver

Borrow powerful document to achieve the event transceiver

Each DOM node actually inherits an event transceiver, so you can directly use the DOM node to do event transceiver

  • inFlppyBirdthereadyIn the listeningplayerDieEvent, and indestroyRemove the
  • Print the previous death and change it to sendplayerDieThe event
class FlppyBird extends GameStage {

	/ *... * /

	pause = false;

	async ready() {
		document.addEventListener("playerDie".this.pauseGame);
	}

	update() {
		if (this.pause) return;
		super.update();
	}

	pauseGame = (e) = > {
		console.error(e.data);
		this.pause = true; }}class Bird extends Sprite {

	/ *... * /

	update() {
		super.update();

		// v is equal to v0 plus a times t squared
		this.speed += this.gravity; // Velocity = velocity + acceleration * time ²

		let top = this.top + this.speed;  // Update the location

		// dieLine should subtract its height because the anchor is in the upper left corner
		const dieLine = this.dieLine - this.size.height;

		// Stop at dieLine if it is greater than dieLine
		if (top > dieLine) {
			top = dieLine;
			// Send a death event
			const event = new Event("playerDie");
			event.data = "It crashed. You're dead.";
			document.dispatchEvent(event);
		}

		this.top = top; }}class PieMgr extends GameObject {

	/ *... * /

	bird;   / / player

	update() {
		super.update();

		/ / move
		// All pies are shifted to the left simultaneously
		const { speed, pieArr } = this;
		pieArr.forEach((pie) = > {
			pie.left -= speed;
			if (pie.left <= -pie.size.width) {  // If you remove the screen
				this.pieArr.splice(this.pieArr.indexOf(pie), 1);    // Remove from the managed list
				this.removeChild(pie);                              // Remove the child node
				ObjectPool.put("pie", pie);                         // Add to the object pool
				return;
			}

			// Check for collisions
			Up and pie. Down are relative to pie, so reconstruct the left and top of the square
			const pieUpBox = {
				left: pie.left,
				top: pie.top + pie.up.top,
				size: pie.up.size,
			}

			const pieDownBox = {
				left: pie.left,
				top: pie.top + pie.down.top,
				size: pie.down.size,
			}
			if (boxCollisionTest(this.bird, pieUpBox) || boxCollisionTest(this.bird, pieDownBox)) {
				// Send a death event
				const event = new Event("playerDie");
				event.data = "Hit a barrier, you're dead.";
				document.dispatchEvent(event); }}); }}Copy the code

Run the case and find that both death modes pause the game properly