内容简介:文章首发于我的上一篇文章:《这个游戏结束时的
文章首发于我的 个人博客
前言
上一篇文章:《 Chrome 小恐龙游戏源码探究九 -- 游戏碰撞检测 》实现了游戏的碰撞检测,这一篇文章中将利用碰撞检测的结果,实现游戏的结束。
绘制 Game Over 面板
这个游戏结束时的 Game Over
面板是通过 GameOverPanel
类绘制的。
定义 GameOverPanel
类:
/** * 游戏结束面板类 * @param {!HTMLCanvasElement} 画布元素 * @param {Object} textImgPos 文字 "Game Over" 在雪碧图中的位置 * @param {Object} restartImgPos 重置按钮在雪碧图中的位置 * @param {!Object} dimensions 游戏画布的尺寸 */ function GameOverPanel(canvas, textImgPos, restartImgPos, dimensions) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.canvasDimensions = dimensions; this.textImgPos = textImgPos; this.restartImgPos = restartImgPos; this.draw(); };
相关的配置参数,以及原型链上的方法:
// 配置参数 GameOverPanel.dimensions = { TEXT_X: 0, // 文字 "Game Over" 的 x 坐标 TEXT_Y: 13, TEXT_WIDTH: 191, // 文字 "Game Over" 的宽度 TEXT_HEIGHT: 11, RESTART_WIDTH: 36, // 重置按钮的宽度 RESTART_HEIGHT: 32, }; GameOverPanel.prototype = { draw: function() { var dimensions = GameOverPanel.dimensions; var centerX = this.canvasDimensions.WIDTH / 2; // 文字 "Game Over" var textSourceX = dimensions.TEXT_X; var textSourceY = dimensions.TEXT_Y; var textSourceWidth = dimensions.TEXT_WIDTH; var textSourceHeight = dimensions.TEXT_HEIGHT; var textTargetX = Math.round(centerX - (dimensions.TEXT_WIDTH / 2)); var textTargetY = Math.round((this.canvasDimensions.HEIGHT - 25) / 3); var textTargetWidth = dimensions.TEXT_WIDTH; var textTargetHeight = dimensions.TEXT_HEIGHT; // 重置按钮 var restartSourceWidth = dimensions.RESTART_WIDTH; var restartSourceHeight = dimensions.RESTART_HEIGHT; var restartTargetX = centerX - (dimensions.RESTART_WIDTH / 2); var restartTargetY = this.canvasDimensions.HEIGHT / 2; textSourceX += this.textImgPos.x; textSourceY += this.textImgPos.y; // 文字 "Game over" this.ctx.drawImage(Runner.imageSprite, textSourceX, textSourceY, textSourceWidth, textSourceHeight, textTargetX, textTargetY, textTargetWidth, textTargetHeight); // 重置按钮 this.ctx.drawImage(Runner.imageSprite, this.restartImgPos.x, this.restartImgPos.y, restartSourceWidth, restartSourceHeight, restartTargetX, restartTargetY, dimensions.RESTART_WIDTH, dimensions.RESTART_HEIGHT); } };
然后需要在游戏结束时,调用 GameOverPanel
类。
在 gameOver
方法中调用 GameOverPanel
类,并更新小恐龙的状态和一些标志位:
Runner.prototype = { // 游戏结束 gameOver: function () { this.stop(); + this.crashed = true; // 小恐龙撞到了障碍物 + this.distanceMeter.achievement = false; // 结束分数闪动特效 + // 更新小恐龙为碰撞状态 + this.tRex.update(100, Trex.status.CRASHED); + // 绘制游戏结束面板 + if (!this.gameOverPanel) { + this.gameOverPanel = new GameOverPanel(this.canvas, + this.spriteDef.TEXT_SPRITE, this.spriteDef.RESTART, + this.dimensions); + } else { + this.gameOverPanel.draw(); + } if (this.distanceRan > this.highestScore) { this.highestScore = Math.ceil(this.distanceRan); this.distanceMeter.setHighScore(this.highestScore); // 保存最高分 } // 重置时间 this.time = getTimeStamp(); }, };
补充数据:
Runner.spriteDefinition = { LDPI: { // ... + RESTART: {x: 2, y: 2}, // 重置游戏按钮 }, };
前面的文章中,为了演示效果,我们把 gameOver
方法的调用临时放在了判断页面是否失焦的 onVisibilityChange
方法中。现在我们就不需要这个临时调用了,删除即可。 gameOver
实际的调用如下:
Runner.prototype = { update: function () { // ... if (this.playing) { // ... // 碰撞检测 var collision = hasObstacles && - checkForCollision(this.horizon.obstacles[0], this.tRex, this.ctx); + checkForCollision(this.horizon.obstacles[0], this.tRex); + if (!collision) { this.distanceRan += this.currentSpeed * deltaTime / this.msPerFrame; if (this.currentSpeed < this.config.MAX_SPEED) { this.currentSpeed += this.config.ACCELERATION; } + } else { + this.gameOver(); + } var playAchievementSound = this.distanceMeter.update(deltaTime, Math.ceil(this.distanceRan)); // ... } // ... }, };
这样就实现了结束游戏后, Game Over
面板的绘制,效果如下:
查看添加和修改的代码, 戳这里
重新开始游戏
想要重新开始游戏,无非就是把保存的数据清零以及把标志位给重置:
Runner.prototype = { // 重新开始游戏 restart: function() { if (!this.raqId) { this.runningTime = 0; // 重置游戏运行时间 this.setPlayStatus(true); // 游戏重置为进行状态 this.paused = false; // 游戏没有暂停 this.crashed = false; // 小恐龙没有撞到障碍物 this.distanceRan = 0; // 重置游戏移动距离(分数) this.currentSpeed = this.config.SPEED; // 重置游戏当前的速度 this.time = getTimeStamp(); // 重置计时器 this.clearCanvas(); // 清空画布 this.distanceMeter.reset(); // 重置分数类 this.horizon.reset(); // 重置背景类 this.tRex.reset(); // 重置小恐龙类 this.invert(true); // 重置页面为没有进行颜色反转 this.update(); // 重置后更新游戏 } }, };
其中 Trex
类上的 reset
方法已经定义过了。 DistanceMeter
、 Horizon
类上的 reset
方法定义如下:
DistanceMeter.prototype = { // 重置当前分数为 '00000' reset: function() { this.update(0); // 更新分数 this.achievement = false; // 分数不进行闪动特效 } }; Horizon.prototype = { // 重置背景类 reset: function() { this.obstacles = []; // 清空障碍物 this.horizonLine.reset(); // 重置地面 this.nightMode.reset(); // 重置夜晚模式 }, };
同样的, HorizonLine
、 NightMode
类上的 reset
方法定义如下:
HorizonLine.prototype = { reset: function() { // 重置两段地面的坐标 this.xPos[0] = 0; this.xPos[1] = HorizonLine.dimensions.WIDTH; }, }; NightMode.prototype = { reset: function() { this.currentPhase = 0; // 重置月期 this.opacity = 0; // 重置夜晚模式中的物体透明度 this.update(false); // 重置夜晚模式位未激活状态 }, };
最后,调用 restart
方法:
Runner.prototype = { onKeyUp: function(e) { var keyCode = String(e.keyCode); var isjumpKey = Runner.keyCodes.JUMP[keyCode]; if (this.isRunning() && isjumpKey) { // 跳跃 this.tRex.endJump(); } else if (Runner.keyCodes.DUCK[keyCode]) { // 躲避状态 this.tRex.speedDrop = false; this.tRex.setDuck(false); + } else if (this.crashed) { + var deltaTime = getTimeStamp() - this.time; + + // 按下回车键或者等待 750 毫秒后,按下空格键,重新开始游戏 + if (Runner.keyCodes.RESTART[keyCode] || + (deltaTime >= this.config.GAMEOVER_CLEAR_TIME && + Runner.keyCodes.JUMP[keyCode])) { + this.restart(); + } + } }, };
效果如下:
查看添加和修改的代码, 戳这里
加载游戏音效
TODO
Demo 体验地址:[]() TODO
游戏的其他要素
到这里,我们已经把游戏的必要功能都实现了。原游戏中,还实现了移动端适配,高分屏的适配,是否需要进入街机模式的处理,游戏画布对浏览器窗口大小的自适应。
这些功能我们就不再实现,感兴趣的可以自行尝试。
结语
利用十多天的业余时间探究了小恐龙游戏的源码,收获很多,也为自己以后开发 H5 游戏提供了一定的思路。
由于水平有限,如果文章存在有歧义或错误的地方,欢迎评论指出。
(完)
上一篇 | 下一篇 | Chrome 小恐龙游戏源码探究九 -- 游戏碰撞检测 | 无 |
以上所述就是小编给大家介绍的《Chrome 小恐龙游戏源码探究完 -- 游戏结束和其他要素》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Chrome 小恐龙游戏源码探究六 -- 记录游戏分数
- Chrome 小恐龙游戏源码探究九 -- 游戏碰撞检测
- Chrome 小恐龙游戏源码探究五 -- 随机绘制障碍
- Chrome 小恐龙游戏源码探究二 -- 让地面动起来
- Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙
- 跨域不完全探究
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。