内容简介:上一篇文章:《在游戏中,小恐龙移动的距离就是游戏的分数。分数每达 100,就会有闪动的特效。首次进行游戏的时候,由于没有记录过游戏的历史得分,所以不会显示最高分,只有当第一次 game over 后才能显示历史最高分。定义分数类:
前言
上一篇文章:《 Chrome 小恐龙游戏源码探究五 -- 随机绘制障碍 》 实现了障碍物仙人掌和翼龙的绘制。这一篇将实现当前分数、最高分数的记录和绘制。
在游戏中,小恐龙移动的距离就是游戏的分数。分数每达 100,就会有闪动的特效。首次进行游戏的时候,由于没有记录过游戏的历史得分,所以不会显示最高分,只有当第一次 game over 后才能显示历史最高分。
分数记录
定义分数类:
/** * 记录移动的距离(分数等于移动距离) * @param {HTMLCanvasElement} canvas 画布 * @param {Object} spritePos 图片在雪碧图中的位置 * @param {Number} canvasWidth 画布的宽度 */ function DistanceMeter(canvas, spritePos, canvasWidth) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.config = DistanceMeter.config; this.spritePos = spritePos; this.x = 0; // 分数显示在 canvas 中的 x 坐标 this.y = 5; this.maxScore = 0; // 游戏分数上限 this.highScore = []; // 存储最高分数的每一位数字 this.digits = []; // 存储分数的每一位数字 this.achievement = false; // 是否进行闪动特效 this.defaultString = ''; // 游戏的默认距离(00000) this.flashTimer = 0; // 动画计时器 this.flashIterations = 0; // 特效闪动的次数 this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS; // 分数的最大位数 this.init(canvasWidth); }
有关的配置参数:
DistanceMeter.config = { MAX_DISTANCE_UNITS: 5, // 分数的最大位数 ACHIEVEMENT_DISTANCE: 100, // 每 100 米触发一次闪动特效 COEFFICIENT: 0.025, // 将像素距离转换为比例单位的系数 FLASH_DURATION: 1000 / 4, // 一闪的时间(一次闪动分别两闪:从有到无,从无到有) FLASH_ITERATIONS: 3, // 闪动的次数 }; DistanceMeter.dimensions = { WIDTH: 10, HEIGHT: 13, DEST_WIDTH: 11, // 加上间隔后每个数字的宽度 };
补充本篇文章中会用到的一些数据:
function Runner(containerSelector, opt_config) { // ... + this.msPerFrame = 1000 / FPS; // 每帧的时间 }, Runner.spriteDefinition = { LDPI: { //... + TEXT_SPRITE: {x: 655, y: 2}, // 文字 }, };
在 DistanceMeter 上添加方法:
DistanceMeter.prototype = { init: function (width) { var maxDistanceStr = ''; // 游戏的最大距离 this.calcXPos(width); // 计算分数显示在 canvas 中的 x 坐标 for (var i = 0; i < this.maxScoreUnits; i++) { this.draw(i, 0); // 第一次游戏,不绘制最高分 this.defaultString += '0'; // 默认初始分数 00000 maxDistanceStr += '9'; // 默认最大分数 99999 } this.maxScore = parseInt(maxDistanceStr); }, calcXPos: function (canvasWidth) { this.x = canvasWidth - (DistanceMeter.dimensions.DEST_WIDTH * (this.maxScoreUnits + 1)); }, /** * 将分数绘制到 canvas 上 * @param {Number} digitPos 数字在分数中的位置 * @param {Number} value 数字的具体值(0-9) * @param {Boolean} opt_highScore 是否显示最高分 */ draw: function (digitPos, value, opt_highScore) { // 在雪碧图中的坐标 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; // 绘制到 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) { // 显示最高分 var hightScoreX = this.x - (this.maxScoreUnits * 2) * DistanceMeter.dimensions.WIDTH; this.ctx.translate(hightScoreX, this.y); } else { // 不显示最高分 this.ctx.translate(this.x, this.y); } this.ctx.drawImage( Runner.imageSprite, sourceX, sourceY, sourceWidth, sourceHeight, targetX, targetY, targetWidth, targetHeight ); this.ctx.restore(); }, /** * 将游戏移动的像素距离转换为真实的距离 * @param {Number} distance 游戏移动的像素距离 */ getActualDistance: function (distance) { return distance ? Math.round(distance * this.config.COEFFICIENT) : 0; }, update: function (deltaTime, distance) { var paint = true; // 是否绘制分数 var playSound = false; // 是否播放音效 // 没有进行闪动特效 if (!this.achievement) { distance = this.getActualDistance(distance); // 分数超出上限时,上限增加一位数。超出上限两位数时,分数置零 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) { // 触发闪动特效 if (distance % this.config.ACHIEVEMENT_DISTANCE == 0) { this.achievement = true; this.flashTimer = 0; playSound = true; } // 分数前面补零来凑位数 var distanceStr = (this.defaultString + distance).substr(-this.maxScoreUnits); this.digits = distanceStr.split(''); } else { // 将默认分数 00000 中的每一位数字存到数组中 this.digits = this.defaultString.split(''); } } else { // 控制特效的闪动次数 if (this.flashIterations <= this.config.FLASH_ITERATIONS) { this.flashTimer += deltaTime; // 第一闪不绘制数字 if (this.flashTimer < this.config.FLASH_DURATION) { paint = false; } // 进行了两闪,闪动次数加一 else if (this.flashTimer > this.config.FLASH_DURATION * 2) { this.flashTimer = 0; this.flashIterations++; } } else { // 闪动特效结束 this.achievement = false; this.flashIterations = 0; this.flashTimer = 0; } } // 绘制当前分 if (paint) { for (var i = this.digits.length - 1; i >= 0; i--) { this.draw(i, parseInt(this.digits[i])); } } // 绘制最高分 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(); }, /** * 将游戏的最高分数存入数组 * @param {Number} distance 游戏移动的像素距离 */ setHighScore: function (distance) { distance = this.getActualDistance(distance); var highScoreStr = (this.defaultString + distance).substr(-this.maxScoreUnits); // 分数前面字母 H、I 在雪碧图中位于数字后面,也就是第 10、11 位置 this.highScore = ['10', '11', ''].concat(highScoreStr.split('')); }, };
下面是对分数类的调用。
首先给 Runner 类添加属性:
function Runner(containerSelector, opt_config) { // ... + this.distanceMeter = null; // 距离计数类 + this.distanceRan = 0; // 游戏移动距离 + this.highestScore = 0; // 最高分 }
然后初始化分数类 DistanceMeter
:
Runner.prototype = { init: function () { // ... // 加载距离计数器类 DistanceMeter this.distanceMeter = new DistanceMeter(this.canvas, this.spriteDef.TEXT_SPRITE, this.dimensions.WIDTH); }, };
更新游戏分数(移动距离):
Runner.prototype = { update: function () { this.updatePending = false; // 等待更新 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)); } // ... }, };
这样就实现了分数的绘制,效果如下:
查看添加的代码, 戳这里
上面定义了保存、绘制游戏最高分的方法,但还没有调用,现在只要在游戏结束时,将分数保存下来,就能实现最高分的绘制:
Runner.prototype = { // 游戏结束 gameOver: function () { this.stop(); if (this.distanceRan > this.highestScore) { this.highestScore = Math.ceil(this.distanceRan); this.distanceMeter.setHighScore(this.highestScore); // 保存最高分 } // 重置时间 this.time = getTimeStamp(); }, };
这里为了演示,当页面失焦时,结束游戏:
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(); } }, };
效果如下:
查看添加的代码, 戳这里
Demo 体验地址: https://liuyib.github.io/pages/demo/games/google-dino/show-score/
上一篇 | 下一篇 | Chrome 小恐龙游戏源码探究五 -- 随机绘制障碍 | Chrome 小恐龙游戏源码探究七 -- 昼夜模式交替 |
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Chrome 小恐龙游戏源码探究九 -- 游戏碰撞检测
- Chrome 小恐龙游戏源码探究完 -- 游戏结束和其他要素
- Chrome 小恐龙游戏源码探究五 -- 随机绘制障碍
- Chrome 小恐龙游戏源码探究二 -- 让地面动起来
- Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙
- 跨域不完全探究
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。