Preface
Last article:< Chrome Dinosaur Game Source Exploration 5 - Random Drawing Obstacles > The rendering of obstacle cactus and pterosaur is realized. This article will record and draw the current score and the highest score.
In the game, the distance a small dinosaur moves is the score of the game. Every time the score reaches 100, there will be a special effect of flickering. When the first game is played, the highest score will not be displayed because the historical score of the game has not been recorded. Only when the first game is over can the highest score be displayed.
Score record
Define score categories:
/** * Record the distance of movement (fraction equals the distance of movement) * @param {HTMLCanvasElement} canvas canvas * @param {Object} spritePos The position of the picture in Sprite * @param {Number} canvasWidth Width of canvas */ function DistanceMeter(canvas, spritePos, canvasWidth) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.config = DistanceMeter.config; this.spritePos = spritePos; this.x = 0; // x coordinates of fractions displayed in canvas this.y = 5; this.maxScore = 0; // Game Score Upper Limit this.highScore = []; // Store every digit with the highest score this.digits = []; // Store every number of points this.achievement = false; // Whether to do flash effects or not this.defaultString = ''; // Default Distance of Game (00000) this.flashTimer = 0; // Animation timer this.flashIterations = 0; // Number of special effect flickers this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS; // Maximum number of fractions this.init(canvasWidth); }
Relevant configuration parameters:
DistanceMeter.config = { MAX_DISTANCE_UNITS: 5, // Maximum number of fractions ACHIEVEMENT_DISTANCE: 100, // Flash effect triggered every 100 meters COEFFICIENT: 0.025, // Coefficient of converting pixel distance to proportional unit FLASH_DURATION: 1000 / 4, // The time of a flash (two flickers in one flicker: from being to not, from nothing to being) FLASH_ITERATIONS: 3, // Number of flickers }; DistanceMeter.dimensions = { WIDTH: 10, HEIGHT: 13, DEST_WIDTH: 11, // Width of each digit after adding intervals };
To supplement some of the data used in this article:
function Runner(containerSelector, opt_config) { // ... + this.msPerFrame = 1000 / FPS; // Time per frame }, Runner.spriteDefinition = { LDPI: { //... + TEXT_SPRITE: {x: 655, y: 2}, // Written words }, };
Add a method to DistanceMeter:
DistanceMeter.prototype = { init: function (width) { var maxDistanceStr = ''; // Maximum Distance of Game this.calcXPos(width); // Calculating the x coordinates of the fraction displayed in canvas for (var i = 0; i < this.maxScoreUnits; i++) { this.draw(i, 0); // The first game, do not draw the highest score this.defaultString += '0'; // Default initial score 00000 maxDistanceStr += '9'; // Default maximum score 99999 } this.maxScore = parseInt(maxDistanceStr); }, calcXPos: function (canvasWidth) { this.x = canvasWidth - (DistanceMeter.dimensions.DEST_WIDTH * (this.maxScoreUnits + 1)); }, /** * Draw fractions on canvas * @param {Number} digitPos The Position of Numbers in Fractions * @param {Number} value The specific value of the number (0-9) * @param {Boolean} opt_highScore Does it show the highest score? */ draw: function (digitPos, value, opt_highScore) { // Coordinates in Sprite var sourceX = this.spritePos.x + DistanceMeter.dimensions.WIDTH * value; var sourceY = this.spritePos.y + 0; var sourceWidth = DistanceMeter.dimensions.WIDTH; var sourceHeight = DistanceMeter.dimensions.HEIGHT; // Coordinates drawn to canvas var targetX = digitPos * DistanceMeter.dimensions.DEST_WIDTH; var targetY = this.y; var targetWidth = DistanceMeter.dimensions.WIDTH; var targetHeight = DistanceMeter.dimensions.HEIGHT; this.ctx.save(); if (opt_highScore) { // Show the highest score var hightScoreX = this.x - (this.maxScoreUnits * 2) * DistanceMeter.dimensions.WIDTH; this.ctx.translate(hightScoreX, this.y); } else { // Not showing the highest score this.ctx.translate(this.x, this.y); } this.ctx.drawImage( Runner.imageSprite, sourceX, sourceY, sourceWidth, sourceHeight, targetX, targetY, targetWidth, targetHeight ); this.ctx.restore(); }, /** * Converting the Pixel Distance of Game Moving to the Real Distance * @param {Number} distance Pixel Distance of Game Moving */ getActualDistance: function (distance) { return distance ? Math.round(distance * this.config.COEFFICIENT) : 0; }, update: function (deltaTime, distance) { var paint = true; // Whether to draw scores or not var playSound = false; // Whether to Play Sound Effect // No flash effects if (!this.achievement) { distance = this.getActualDistance(distance); // When the score exceeds the upper limit, the upper limit is increased by one digit. When two digits above the upper limit are exceeded, the fraction is set to zero. if (distance > this.maxScore && this.maxScoreUnits === this.config.MAX_DISTANCE_UNITS) { this.maxScoreUnits++; this.maxScore = parseInt(this.maxScore + '9'); } else { this.distance = 0; } if (distance > 0) { // Trigger flicker effect if (distance % this.config.ACHIEVEMENT_DISTANCE == 0) { this.achievement = true; this.flashTimer = 0; playSound = true; } // Complete the zero before the score to make up the number of digits var distanceStr = (this.defaultString + distance).substr(-this.maxScoreUnits); this.digits = distanceStr.split(''); } else { // Store each digit in the array with the default score of 00000 this.digits = this.defaultString.split(''); } } else { // Control the number of flickers of special effects if (this.flashIterations <= this.config.FLASH_ITERATIONS) { this.flashTimer += deltaTime; // The first flash does not draw numbers if (this.flashTimer < this.config.FLASH_DURATION) { paint = false; } // Two flickers were made and the number of flickers was increased by one. else if (this.flashTimer > this.config.FLASH_DURATION * 2) { this.flashTimer = 0; this.flashIterations++; } } else { // Flash Special Effect End this.achievement = false; this.flashIterations = 0; this.flashTimer = 0; } } // Draw the current score if (paint) { for (var i = this.digits.length - 1; i >= 0; i--) { this.draw(i, parseInt(this.digits[i])); } } // Draw the highest score this.drawHighScore(); return playSound; }, drawHighScore: function () { this.ctx.save(); this.ctx.globalAlpha = 0.8; for (var i = this.highScore.length - 1; i >= 0; i--) { this.draw(i, parseInt(this.highScore[i], 10), true); } this.ctx.restore(); }, /** * Store the highest score of the game in an array * @param {Number} distance Pixel Distance of Game Moving */ setHighScore: function (distance) { distance = this.getActualDistance(distance); var highScoreStr = (this.defaultString + distance).substr(-this.maxScoreUnits); // The letters H and I in front of the score are behind the numbers in the Sprite chart, that is, positions 10 and 11. this.highScore = ['10', '11', ''].concat(highScoreStr.split('')); }, };
The following is a call to the score class.
First, add attributes to the Runner class:
function Runner(containerSelector, opt_config) { // ... + this.distanceMeter = null; // Distance Counting Class + this.distanceRan = 0; // Game Moving Distance + this.highestScore = 0; // Highest score }
Then initialize the score class DistanceMeter:
Runner.prototype = { init: function () { // ... // Loading Distance Meter Class this.distanceMeter = new DistanceMeter(this.canvas, this.spriteDef.TEXT_SPRITE, this.dimensions.WIDTH); }, };
Update game scores (moving distance):
Runner.prototype = { update: function () { this.updatePending = false; // Waiting for updates if (this.playing) { // ... + this.distanceRan += this.currentSpeed * deltaTime / this.msPerFrame; if (this.currentSpeed < this.config.MAX_SPEED) { this.currentSpeed += this.config.ACCELERATION; } + var playAchievementSound = this.distanceMeter.update(deltaTime, + Math.ceil(this.distanceRan)); } // ... }, };
In this way, the score drawing is realized, and the effect is as follows:
Look at the added code. Poke here
The method of saving and drawing the highest score of the game is defined above, but it has not been invoked yet. Now, as long as the score is saved at the end of the game, the drawing of the highest score can be achieved:
Runner.prototype = { // Game over gameOver: function () { this.stop(); if (this.distanceRan > this.highestScore) { this.highestScore = Math.ceil(this.distanceRan); this.distanceMeter.setHighScore(this.highestScore); // Keep the highest score } // reset time this.time = getTimeStamp(); }, };
Here for demonstration, when the page is out of focus, end the game:
Runner.prototype = { onVisibilityChange: function (e) { if (document.hidden || document.webkitHidden || e.type == 'blur' || document.visibilityState != 'visible') { this.stop(); + this.gameOver(); } else if (!this.crashed) { this.play(); } }, };
The results are as follows:
Look at the added code. Poke here
Demo Experience Address: https://liuyib.github.io/pages/demo/games/google-dino/show-score/
Last article | Next article | Chrome Dinosaur Game Source Exploration 5 - Random Drawing Obstacles | Chrome Dinosaur Game Source Exploration |