The introduction

All right, in last chapter we’ve done ✌ static scenes, all ready except write logic 😧. Let’s cut to the chase.

Start page logic

Since the start page is boring, there is only one button to start the game, so we just need to add an event listener on the button. The logic is that when the touch event occurs, we will add SceneGame to the stage and remove the BeginScene from the stage as follows:

// SceneGame.ts
public beginBtn:eui.Button;
private initBeginbtn. once(egret.touchEvent.TOUCH_TAP, this.start, this); } privatestart() {// Add the game scene this.parent. AddChild (new SceneGame()); // Remove the initial scene this.parent. RemoveChild (this); }Copy the code

Game page logic

Now we click the start button can jump to the game interface, the next is the game logic on πŸ’Ž, is also the essence of this article πŸ’ͺ, roll up your sleeves to knock!

Variable declarations

There are a bunch of variables to declare here. For details, see the source code at the end of the article. I won’t copy all of them.

// the main variable declaration in scenegame. ts
// The current box (the latest box is the target box to jump over)
private currentBlock: eui.Image;
// Next box orientation (1 to the right, -1 to the left)
public direction: number = 1;
// The Angle value of tanΞΈ can be adjusted by yourself, and the direction can be used to calculate the coordinates of the next box
public tanAngle: number = 0.556047197640118;
// The maximum and minimum (horizontal) distances of random boxes
private minDistance = 220;
private maxDistance = 320;
// The jump distance (calculated by the time you press) is the horizontal distance
public jumpDistance: number = 0;
// Left jump point (fixed, adjustable)
private leftOrigin = { "x": 180."y": 350 };
// Right side jump point (fixed, adjustable)
private rightOrigin = { "x": 505."y": 350 };
Copy the code

Initialization interface

First we have to look at what the initial interface of the game looks like, rightinitWhat is written inside the function:As you can see from the image above, all we need to do is generate the cube, and then set the position of the little person and the cube. Note that the position of the first square and the little man is fixed, in the lower left; By default, the first jump is to the right, as is the second square. Why to fix the initial position, I think it is mainly convenient, save you to judge the calculation (there is no need to πŸ€·β™€οΈπŸ€·β™‚οΈ), the following will explain a wave. You can also take a look at the official wechat jump jump game, its first position and direction is also fixed.

Ok, let’s take a quick look at how the next block is generated and added to the stage. (Something that is repeated is usually written as a class or methodnew Image()Same, set againsrcFor details, see the following code:

✌ // Create a block private createBlock(): eui.image {✌ // random background pictureletn = Math.floor(Math.random() * this.blockSourceNames.length); // instantiate and add to the stageletblockNode = new eui.Image(); blockNode.source = this.blockSourceNames[n]; this.blockPanel.addChild(blockNode); // Set the anchor point of the block (not the center point of the image, but the center point of the box) blocknode.anchoroffsetx = 222; blockNode.anchorOffsetY = 78; blockNode.touchEnabled =false; // Add the new block to blockArr to manage this.blockarr.push (blockNode);returnblockNode; } // Add a square and set xy value privateaddBlock() {// Create a boxletblockNode = this.createBlock(); // Random horizontal position (a number between the maximum and minimum values, because the screen is so big)let distance = this.minDistance + Math.random() * (this.maxDistance - this.minDistance);
    if(this.direction > 0) {// Go to the right blocknode. x = this.currentBlock.x + distance; blockNode.y = this.currentBlock.y - distance * this.tanAngle; }else{// Jump left blocknode. x = this.currentBlock.x - distance; blockNode.y = this.currentBlock.y - distance * this.tanAngle; } this.currentBlock = blockNode; }Copy the code

Ok, now that we know how to create a block, let’s look at the code in our init function and see what happens when we initialize it:

// SceneGame.ts
private init() {// All box resources this.blockSourcenames = ["block1_png"."block2_png"."block3_png"]; PushVoice = res.getres (this.pushVoice = res.getres ('push_mp3');
    this.jumpVoice = RES.getRes('jump_mp3'); // Initialize the scene (square and small person) this.initblock (); / / add touch events this. BlockPanel. TouchEnabled =true; this.blockPanel.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.onTapDown, this); this.blockPanel.addEventListener(egret.TouchEvent.TOUCH_END, this.onTapUp, this); // Egret. startTick(this.computeDistance, this); } privateinitBlockThis.currentblock = this.createBlock(); this.currentBlock = this.createBlock(); this.currentBlock.x = this.leftOrigin.x; this.currentBlock.y = this.stage.stageHeight - this.leftOrigin.y; this.blockPanel.addChild(this.currentBlock); // Initialize the player (the anchor point of the player is in the middle of the bottom) this.player.y = this.currentBlock.y; this.player.x = this.currentBlock.x; this.player.anchorOffsetX = this.player.width / 2; this.player.anchorOffsetY = this.player.height - 20; this.blockPanel.addChild(this.player); // initialize score this.score = 0; this.scoreLabel.text = this.score.toString(); this.blockPanel.addChild(this.scoreLabel); // Initialize direction this.direction = 1; // Add the next box this.addblock (); }Copy the code

The code comments above should be pretty clear, let’s focus on the difficulty egret.startTick(this.computeDistance, this). The startTick API will call this.computeDistance at 60 frames. Don’t understand? It doesn’t matter. I’ll just say setInterval. This.putedistance the main purpose of this method is to calculate the horizontal distance of the jump by pressing the time. It should be easy to understand the following code:

// SceneGame.ts
// This function needs to return a Boolean (specified). It's not clear what it does, but it doesn't affect how we write code
private computeDistance(timeStamp:number):boolean {
    // timeStamp is an incremented time (run to the current elapsed time, e.g. 0,500,1000... , unit ms)
    let now = timeStamp;
    let time = this.time;
    let pass = now - time;
    pass /= 1000;
    if (this.isReadyJump) {
        // Calculate the jump distance by pressing time (s = vt)
    	this.jumpDistance += 300 * pass; // 300 is a debugged parameter that can be changed by itself
    }
    this.time = now;
    return true;
}
Copy the code

In fact, the above content is paving the way, the following officially began to write the logic of the game part 😭😭😭, take a deep breath, the state of mind to be steady, the car or to continue to drive.

Before takeoff

That is, when we touch the interface, what need to do, first in mind πŸ€”… That’s right, just two things. Play the press sound and add the deformation on the y axis to make it look more realistic. The code is as follows:

// SceneGame.ts
private onTapDown() {
    // Play the sound, the parameters are (from where to play, play times)
    this.pushSoundChannel = this.pushVoice.play(0.1);
    // Make the dwarf shorter to save energy, that is, scale the Y-axis
    egret.Tween.get(this.player).to({scaleY: 0.5}, 3000);
    // Jump mark
    this.isReadyJump = true;
}
Copy the code

Coming up

When our fingers leave the screen, we need to do the following: 1. Make the stage unclickable; 2. Switch the sound; 3. Calculate the horizontal distance of jumping by pressing time; 4, the villain jump along the curve and rotate; Code first to explain:

// SceneGame.ts
private onTapUp() {
    if (!this.isReadyJump) return;
    if (!this.targetPos) this.targetPos = new egret.Point(); // point is a point with xy and so on
    
    // As soon as you release your hand, the avatar should jump. At this point, you should first stop clicking on the screen and switch the sound
    this.blockPanel.touchEnabled = false;
    this.pushSoundChannel.stop();
    this.jumpVoice.play(0.1);
    
    // Clear all animations
    egret.Tween.removeAllTweens();
    this.isReadyJump = false;
    
    // Calculate the coordinates of the drop point
    this.targetPos.x = this.player.x + this.direction * this.jumpDistance;
    this.targetPos.y = this.player.y + this.direction * this.jumpDistance * (this.currentBlock.y - this.player.y) / (this.currentBlock.x - this.player.x);
    
    // Execute the jump animation
    egret.Tween.get(this).to({ factor: 1 }, 400).call(() = > { // This represents the Bezier curve. In 400 milliseconds, the factor attribute of this will slowly approach the value of 1. The factor here is the t attribute of the curve, which is the closed interval from 0 to 1.
    	this.player.scaleY = 1;
    	this.jumpDistance = 0;
    	// Determine if the jump was successful
    	this.checkResult();
    });
    // Execute the little man flip animation, first handle the rotation center point
    this.player.anchorOffsetY = this.player.height / 2;
    egret.Tween.get(this.player)
    	.to({ rotation: this.direction > 0 ? 360 : -360 }, 200)
    	.call(() = > { this.player.rotation = 0 })
    	.call(() = > { this.player.anchorOffsetY = this.player.height - 20; });
}
// Add factor's set and get methods
public get factor() :number {
    return 0;
}
// The getter here makes the factor property start at 0, with the 1 passed in to tween, so that it fits the t interval in the formula.
// The important thing is that in the setter, the Player object is the display object to which we apply the quadratic Bezier curve, and in the setter, the formula for assigning the xy property of the Player object is exactly the quadratic Bezier curve formula listed earlier.
public set factor(t:number) {
    // Just a formula
    this.player.x = (1 - t) * (1 - t) * this.player.x + 2 * t * (1 - t) * (this.player.x + this.targetPos.x) / 2 + t * t * (this.targetPos.x);
    this.player.y = (1 - t) * (1 - t) * this.player.y + 2 * t * (1 - t) * (this.targetPos.y - 300) + t * t * (this.targetPos.y);
}
Copy the code

What’s harder to understand is how πŸƒβ™€οΈ little πŸƒ moves along the Bezier curve, which is a confusing mathematical term. Here’s a little analysis. Look at theegret.Tween.get(this).to({ factor: 1 }, 400)The inside of thefactorWhat does that mean?factorPhi is a property, you can think of it as a variable, it starts at 0, and we use phiegret.TweenThe easing function letsfactorFrom 0 to 1 in 400 ms,factorThe value of delta has changed according topublic set factor(t:number) {}, the coordinates of the little man will also change, so the little man will move. Give it a good taste.

And you might say, well, why are the coordinates of the little guy written that way? In fact, this is a formula, what formula, as shown below:What is this formula? It’s the following:A little familiar? Wait βœ‹, P0, P1, P2Is what? There are three coordinate points, and it will make sense if we look at the following picture:We can see from the figure above that P0It’s the coordinates of the little man, P2It’s the coordinates of the target point, P1Is a point above the middle of the two (you can modify), and then plug in the above formula. If you’re still confused, it doesn’t matter, it doesn’t matter, just know that if we have three points (starting point, middle point and end point) and plug in the formula above, we can draw a Bezier curve. Once again a good experience 😬, if you have the power to baidu to understand the Bessel curve. If you really can’t understand it, it doesn’t matter, you don’t use it, directly translate the SIMS to the end, don’t want any jumping effect, just like the following:

egret.Tween.get(this.player).to({ x: this.targetPos.x, y: this.targetPos.y }, 400).call(() = > {})
Copy the code

See here is really not easy ah, across a barrier, have to give their own drum palm πŸ‘πŸ‘πŸ‘πŸ‘πŸ‘

After the jump

Without stopping, comrades please continue to refueling, dawn is at hand 🌞, fighting. Now, the villain has jumped to the target square, at this time we need to judge whether the landing position of the villain is within the allowed error range, in order to judge the success and failure, first look at the following picture:If we know the position of the little man and the square, we can calculate the error of the two (i.e. the hypotenuse). If it is less than a certain range, we consider the jump to be successful. The code is as follows:

// SceneGame.ts
private checkResult() {
    // Actual error
    let err = Math.pow(this.player.x - this.currentBlock.x, 2) + Math.pow(this.player.y - this.currentBlock.y, 2)
    // Maximum error allowed
    const MAX_ERR_LEN = 90 * 90;
    if (err <= MAX_ERR_LEN) { // Jump successful
    	// Update the score
    	this.score++;
    	this.scoreLabel.text = this.score.toString();
    	// The direction to beat
    	this.direction = Math.random() > 0.5 ? 1 : -1;
    	// The distance from the current block to the corresponding jump point
    	let blockX, blockY;
    	blockX = this.direction > 0 ? this.leftOrigin.x : this.rightOrigin.x;
    	blockY = this.stage.stageHeight / 2 + this.currentBlock.height;
    	// The point to which the SIMS move
    	let diffX = this.currentBlock.x - blockX;
    	let diffY = this.currentBlock.y - blockY;
    	let playerX, playerY;
    	playerX = this.player.x - diffX;
    	playerY = this.player.y - diffY;
    	// Update the page to update all square positions
    	this.updateAll(diffX, diffY);
    	// Update the position of the SIMS
    	egret.Tween.get(this.player).to({
    		x: playerX,
    		y: playerY
    	}, 800).call(() = > {
    		// Start creating the next block
    		this.addBlock();
    		// Make the screen clickable again;
    		this.blockPanel.touchEnabled = true; })}else { // Jump failed
    	this.restartBtn.addEventListener(egret.TouchEvent.TOUCH_TAP, this.reset, this);
    	this.overPanel.visible = true;
    	this.overScoreLabel.text = this.score.toString();
    }
}
private updateAll(x, y) {
    egret.Tween.removeAllTweens();
    for (var i: number = this.blockArr.length - 1; i >= 0; i--) {
        var blockNode = this.blockArr[i];
        // The center of the box (not the image) is to the left or right of the screen or below the screen
        if (blockNode.x + blockNode.width - 222 < 0 || blockNode.x - this.stage.stageWidth - 222 > 0 || blockNode.y - this.stage.stageHeight - 78 > 0) {
        // Block off screen, removed from display list
        if (blockNode) this.blockPanel.removeChild(blockNode);
        this.blockArr.splice(i, 1);
        } else {
        // If the screen is not out, move
        egret.Tween.get(blockNode).to({
        	x: blockNode.x - x,
        	y: blockNode.y - y
        }, 800)}}}Copy the code

Let’s start with the jump failure case. Obviously, we need to update the score to the end screen and display the end screen, as well as add event listeners to the button in the end screen. In the case of a successful jump, all we need to do is update the score, randomly go in the next direction, move all the cubes and the little people, and create the next cube. The difficulty of this step lies in how to move the picture, so it is necessary to install 13 😎.

First we thought that all things move together have a common place is: everyone will move to the left or right the same distance, the distance of the move upwards or downwards as, so we just need to know how to move one square, move the x axis has how many, how much move y, squares and other SIMS could not move the same distance is ok? And can be well experienced πŸ€”.

So now our first task is to figure out how to move one of the cubes. Let’s take a look at this picture:It is important that we jump from one of these two fixed points (self-tuning positions). Also said to the beginning, why will be fixed at the start of the squares on the left, in fact also can put the right, but must be one of the two attachment points, so that when we move squares have a reference point, as shown in the right of the above, after the dog jump the square where the need to move to one of the jumping point, because the next direction to the left, So we will move the square where the little man is to the jump point on the right. That makes things easy. The square where the villain is and the coordinate value of the right jumping point have, a reduction can be calculateddiffY ε’Œ diffX, and then do a for loop for each block array, all moving the same distance, and the little people are the same. ✌ finish moving and regenerate into the next square.

It is not easy to see here, give readers a few big applause πŸ‘πŸ‘πŸ‘πŸ‘, really excellent!

Run the game

Let’s open Egret Launcher and click Publish Settings, as shown below:Select wechat mini game, click “Set to publish by default”, enter your own AppID (you can register one on the mini program website, soon), write a name, and click “OK” :The following popover will pop up:We click the use of wechat developer tools open (if you need to install wechat developer tools), you can preview the effect of the game written by yourself, like the following. Earphones!As a bonus, you may feel stuck while playing, but it doesn’t matter, we just need to change the game’s default frame rate, like this:

conclusion

So far, to have more rough more rough jump a jump small game can run up, but also what, hurriedly start to play, play their own game, feeling is really not (waste) general. Of course, there are many problems, such as adaptation, some phone size prone to black edge (ugly); Or the details are not perfect (you can try to change them yourself); The function is not perfect (try adding it yourself). But these are not important, important is the game ideas, ideas is the most valuable, and the difference between people reflected πŸ˜‚. Follow-up, I will add sharing and ranking functions on the basis of this game, mainly for micro channel games run a relatively complete process, so there is the third chapter 😳 (a total of three should be, can not be more), then the next period goodbye sa πŸ‘‹πŸ‘‹πŸ‘‹ college. Source address: github.com/lgq627628/e…