The introduction
The previous chapter mainly describes the creation and use of pixi tiling wizard and parallax scrolling, this chapter mainly describes the optimization and new functions based on the previous demo.
directory
-
New features
1.1 fractional && speed
1.2 Upper Barrier
1.3 Collision Detection
1.4 2
1.5 HP
1.6 score
-
The setup code
-
conclusion
1. New functions
1.1 fractional && speed
The score here is a little lazy, here is a direct cumulative operation in ticker, thinking about how many points can be achieved by the score, the overall speed of the game will increase a stage, of course, can also avoid obstacles to get points, if there are gold coins and other things can be further optimized.
app.ticker.add(() = > {
// add up the score
$('.score-ctn').text(` score:${score += 1}`);
// Increase the speed
score > 10000 && score < 20000 && (speed = 11);
score > 20000 && score < 30000 && (speed = 12);
score > 30000 && score < 40000 && (speed = 13);
score > 40000 && (speed = 14);
// Scroll indefinitely
bgSpr.tilePosition.x -= 1;
bgSpr.tilePosition.x %= PIXI.Loader.shared.resources['bg2_2'].texture.width;
/ / collision
bump(role, monster) && (roleSmoothie.update = inverted.bind(this.3));
});
Copy the code
1.2 Upper Barrier
The top obstacle is the same as the monster, but in a different position, change the collision feedback when doing collision detection. Setup () new code:
let column = new PIXI.Sprite(PIXI.Loader.shared.resources['column'].texture);
let columnSmoothie = null; // The overhead barrier moves
column.position.set(7700.0);
app.stage.addChild(column);
// Foreground move
columnSmoothie = new Smoothie({
engine: PIXI,
renderer: app.renderer,
root: app.stage,
update: translate.bind(this, column, speed)
});
columnSmoothie.start();
Copy the code
1.3 Collision Detection
Collision detection and collision here to land obstacles feedback is different, when collision to land is directly deduct a little life value, the collision to the above obstacles will not directly deduct life values, but with the mobile launch screen his characters above obstacles will deduct life value, unlike collision to land barrier here above cannot be directly through the obstruction to the latter can pass through, However, health will be deducted directly.
The collision detection idea here is also relatively simple, Land obstacle will return true as long as the character’s x and y axis position intersects with the x and Y axis of the obstacle. It should be noted that the center point of the Sprite is now directly below, and the width / 2 of the Sprite should be added to the collision detection point, and the height of the obstacle should be subtracted from the Y value when the jump collision detection is performed. Returns true if the X-axis minus the obstacle X-axis is greater than or equal to half the negative width of the obstacle and less than half the width of the obstacle and y minus the obstacle y minus the obstacle height is greater than or equal to 20.
Since Sprite tiles are rectangular, it is possible to hit an extra right Angle of the tile during the jump, so a rough subtracting of 20 is considered to be at least zero. Circular collision detection can also be done to avoid right-angle misjudgment.
// Land barrier
function bottombump (spr1, spr2) {
let spr1X = spr1.x + spr1.width / 2;
let spr2Y = spr2.y - spr2.height;
return spr1X - spr2.x <= spr2.width / 2 && spr1X - spr2.x >= -spr2.width / 2 && spr1.y - spr2Y >= 20? true: false;
}
// Overhead barrier
function topbump (spr1, spr2) {
return spr1.x - spr2.x < 30 && spr1.x - spr2.x > -30 && (spr1.y - spr1.height) - (spr2.y + spr2.height) <= 0? true: false;
}
Copy the code
Effect preview:
1.4 2
The second jump is triggered by pressing the jump button again before the first jump is completed and the drop frame is completed. The rest of the jump cannot be triggered. The jump animation configuration is defined at the top
One idea is to pre-define an animation frame with subscripts starting at 0 and ending at 4 frames. When the subscript is judged to be less than 4 and the height of the jump does not exceed a certain value, the subscript is accumulated. When the character’s Y-axis decreases, the y value increases and falls when the subscript is greater than 4. In the last frame, the subscript is restored to 0 to switch the running state.
The second jump requires two variables for judgment, one is used to record the number of clicks and jumps, and the other is used to judge whether the second jump is made. The person who jumps twice in a row is just before the fall of the first jump, and the height of the second jump is set lower than that of the first jump. After the second jump is completed, the person is at the highest point. Then add a jump animation on frame 5 to continue the fall of a jump.
let roleSprJumpIndex = 0;// a runout subscript
/ / jump
$('.jump').on('touchstart'.(e) = > {
if (jumpNum < 2) { // Prohibit multiple jumps
if(! isJump) { roleSmoothie.update = jump.bind(this); / / a jump
isJump = true;
} else {
roleSmoothie.update = jump2.bind(this); / / 2
isJump = false;
}
}
jumpNum++;
})
/ / a jump
function jump () {
role.texture = PIXI.Loader.shared.resources[config.jump[roleSprJumpIndex]].texture;
/ / jump
if (roleSprJumpIndex <= 4 && role.position.y > 285) {
roleSprJumpIndex++;
role.position.y -= 40;
isAction = false;
}
/ / the whereabouts
if (roleSprJumpIndex > 4 ) {
if (role.position.y < 465) {
role.position.y += 35;
}
roleSprJumpIndex++;
isAction = true;
}
/ / to the ground
if (roleSprJumpIndex > 8) {
roleSprJumpIndex = 0;
role.position.y = 465;
isAction = true;
jumpNum = 0; // Reset the number of jumps
isJump = false;
roleSmoothie.update = go.bind(this); // Running state}}/ / 2
function jump2(){
role.texture = PIXI.Loader.shared.resources[config.jump2[roleSprJumpIndex2]].texture;
if (roleSprJumpIndex2 < 6) {
roleSprJumpIndex2++;
role.position.y -= 15;
} else {
roleSprJumpIndex = 5;
roleSprJumpIndex2 = 0;
roleSmoothie.update = jump.bind(this); }}Copy the code
Effect:
1.5 HP
Health in each collision is deducted a bit, ticker collision feedback added code:
Here, a bit of health will be deducted after being pushed out of the screen by the obstacle above, and the character will directly return to the original position. If the character slides to avoid the obstacle above before pushing out of the screen, the x axis of the character will gradually increase to the original position.
// Land obstacle feedback
if (isBottomBump || isBottomBump2) {
role.tint = 0xFFFF660;
if (isBlood && bloodNum >= 0) {
bloodArr[bloodNum].style.display = 'none';
bloodNum--;
isBlood = false; }}else {
role.tint = 0xFFFFFF;
isBlood = true;
}
// Top obstacle feedback
if (topBupm) {
role.x = column.x - 30;
if (role.x < -100) {
bloodArr[bloodNum].style.display = 'none';
role.x = 400; bloodNum--; }}// increment to the original position
if (role.x < 400) {
role.x = role.x + 1;
}
Copy the code
Effect:
1.6 score
I found two sound effects online, one background music, one button sound, plus sound effects to make the experience not so dull.
Howler.js is very simple to use:
// Background music
let bgBgm = new Howl({
src: './demo_bg.mp3'.loop: true // Whether to loop
});
bgBgm.play(); / / play
// Button sound
let btnBgm = new Howl({
src: './demo2.mp3'.loop: false
});
Copy the code
The button event triggers play.
2. Setup code
function setup () {
/ / the background
let bgSpr = new PIXI.extras.TilingSprite(PIXI.Loader.shared.resources['bg'].texture, app.renderer.width, app.renderer.height);
/ / outlook
let bridge = new PIXI.extras.TilingSprite(PIXI.Loader.shared.resources['bridge'].texture, 1600.437);
/ / character
let role = new PIXI.Sprite(PIXI.Loader.shared.resources['role'].texture);
/ / the monster
let monster = new PIXI.Sprite(PIXI.Loader.shared.resources['monster'].texture);
let monster2 = new PIXI.Sprite(PIXI.Loader.shared.resources['monster2'].texture);
// Overhead obstruction
let column = new PIXI.Sprite(PIXI.Loader.shared.resources['column'].texture);
let roleSmoothie = null; // Character animation
let monsterSmoothie = null; // Monster animation
let monster2Smoothie = null;
let bridgeSmoothie = null; // Foreground animation
let columnSmoothie = null; // Animation of obstacles above
let roleSprGoIndex = 0; // walk action picture subscript
let roleSprRunIndex = 0; // Run action picture subscript
let roleSprJumpIndex = 0; // runout is used to subscript the image
let roleSprJumpIndex2 = 0;
let roleSprInverIndex = 0; // reverse action picture subscript
let speed = 10; // Roll speed
let jumpNum = 0; // Number of jumps
let isJump = false; // Jump state
let isBlood = true;
let bloodNum = 2; // Health subscript
let bloodArr = $('.blood-ctn').children(); // Health array
let score = 0; / / score
let isAction = true; // Action state
// Background music
let bgBgm = new Howl({
src: './demo_bg.mp3'.loop: true // Whether to loop
});
bgBgm.play(); / / play
// Button sound
let btnBgm = new Howl({
src: './demo2.mp3'.loop: false
});
/ / center
role.anchor.set(0.5.1);
monster.anchor.set(0.5.1);
monster2.anchor.set(0.5.1);
// Scale
role.scale.set(1.5.1.5);
monster2.scale.set(0.9.0.9);
/ / position
role.position.set(400.465);
monster.position.set(2000.465);
monster2.position.set(3200.465);
bridge.position.set(0.440);
column.position.set(7700.0);
// Add to the stage
app.stage.addChild(bgSpr, bridge, role, monster, monster2, column);
/ / translation
function translate (spr, num) {
spr.tilePosition.x -= num;
spr.tilePosition.x %= PIXI.Loader.shared.resources['prospect'].texture.width;
};
// The monster moves
function monsterTranslate (spr, num, x) {
spr.position.x -= num;
spr.position.x < -x && (spr.position.x = 1600);
};
/ / run
function go () {
role.texture = PIXI.Loader.shared.resources[config.go[roleSprGoIndex]].texture;
roleSprGoIndex < 6? roleSprGoIndex++ : roleSprGoIndex = 0;
};
/ / jump
function jump () {
role.texture = PIXI.Loader.shared.resources[config.jump[roleSprJumpIndex]].texture;
if (roleSprJumpIndex <= 4 && role.position.y > 285) {
roleSprJumpIndex++;
role.position.y -= 40;
isAction = false;
}
if (roleSprJumpIndex > 4 ) {
if (role.position.y < 465) {
role.position.y += 35;
}
roleSprJumpIndex++;
isAction = true;
}
if (roleSprJumpIndex > 8) {
roleSprJumpIndex = 0;
role.position.y = 465;
isAction = true;
jumpNum = 0;
isJump = false;
roleSmoothie.update = go.bind(this); }}/ / 2
function jump2(){
role.texture = PIXI.Loader.shared.resources[config.jump2[roleSprJumpIndex2]].texture;
if (roleSprJumpIndex2 < 6) {
roleSprJumpIndex2++;
role.position.y -= 15;
} else {
roleSprJumpIndex = 5;
roleSprJumpIndex2 = 0;
roleSmoothie.update = jump.bind(this); }}/ / slide
function slip (num) {
role.texture = PIXI.Loader.shared.resources['sprite4_0'].texture;
}
// The character moves
roleSmoothie = new Smoothie({
engine: PIXI,
renderer: app.renderer,
root: app.stage,
fps: 8.update: go.bind(this)}); roleSmoothie.start();// The monster moves
monsterSmoothie = new Smoothie({
engine: PIXI,
renderer: app.renderer,
root: app.stage,
update: monsterTranslate.bind(this, monster, 7.100)}); monsterSmoothie.start();// Foreground move
prospectSmoothie = new Smoothie({
engine: PIXI,
renderer: app.renderer,
root: app.stage,
update: translate.bind(this, prospectSpr, 3)}); prospectSmoothie.start();// The column moves
columnSmoothie = new Smoothie({
engine: PIXI,
renderer: app.renderer,
root: app.stage,
update: monsterTranslate.bind(this, column, speed)
});
columnSmoothie.start();
// Jump events
$('.jump').on('touchstart'.(e) = > {
if (jumpNum < 2) {
if(! isJump) { roleSmoothie.update = jump.bind(this);
isJump = true;
} else {
roleSmoothie.update = jump2.bind(this);
isJump = false;
}
}
jumpNum++;
btnBgm.play();
});
// Drop events
$('.slip').on('touchstart'.(e) = > {
roleSmoothie.update = slip.bind(this);
roleSprJumpIndex = 0;
roleSprJumpIndex2 = 0;
jumpNum = 0;
isJump = false;
btnBgm.play();
});
// End of slide
$('.slip').on('touchend'.(e) = > {
roleSmoothie.update = go.bind(this);
});
app.ticker.add(() = >{$('.score-ctn').text(` score:${score += 1}`);
// Increase the speed
score > 10000 && score < 20000 && (speed = 11);
score > 20000 && score < 30000 && (speed = 12);
score > 30000 && score < 40000 && (speed = 13);
score > 40000 && (speed = 14);
// Scroll indefinitely
bgSpr.tilePosition.x -= 1;
bgSpr.tilePosition.x %= PIXI.Loader.shared.resources['bg2_2'].texture.width;
isBottomBump = bottombump(role, monster);
isBottomBump2 = bottombump(role, monster2);
topBupm = topbump(role, column);
// Monster collision
if (isBottomBump || isBottomBump2) {
role.tint = 0xFFFF660;
if (isBlood && bloodNum >= 0) {
bloodArr[bloodNum].style.display = 'none';
bloodNum--;
isBlood = false; }}else {
role.tint = 0xFFFFFF;
isBlood = true;
}
// Column collision
if (topBupm) {
role.x = column.x - 30;
if (role.x < -100) {
bloodArr[bloodNum].style.display = 'none';
role.x = 400; bloodNum--; }}if (role.x < 400) {
role.x = role.x + 1; }})});// Monster collision
function bottombump (spr1, spr2) {
let spr1X = spr1.x + spr1.width / 2;
let spr2Y = spr2.y - spr2.height;
return spr1X - spr2.x <= spr2.width / 2 && spr1X - spr2.x >= -spr2.width / 2 && spr1.y - spr2Y >= 20? true: false;
}
// Column collision
function topbump (spr1, spr2) {
return spr1.x - spr2.x < 30 && spr1.x - spr2.x > -30 && (spr1.y - spr1.height) - (spr2.y + spr2.height) <= 0? true: false;
}
Copy the code
Project link: Demo
3, summarize
This demo for now, though it’s not a difficult point, but it is only belong to can run up and coarser, many details still need to optimize, continue to do, of course, there must be a challenge, such as the zulus are fixed, need to change to be random, and pillars and couldn’t be a monster on the Y axis, There are also some new advanced features like gold coins, flying, broken Bridges and so on.