内容简介:上一篇文章:《在游戏中,小恐龙移动的距离就是游戏的分数。分数每达 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 小恐龙游戏源码探究八 -- 奔跑的小恐龙
- 跨域不完全探究
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
ActionScript 3.0 Cookbook
Joey Lott、Darron Schall、Keith Peters / Adobe Dev Library / 2006-10-11 / GBP 28.50
Well before Ajax and Microsoft's Windows Presentation Foundation hit the scene, Macromedia offered the first method for building web pages with the responsiveness and functionality of desktop programs......一起来看看 《ActionScript 3.0 Cookbook》 这本书的介绍吧!