首页 > 代码库 > Chrome自带恐龙小游戏的源码研究(一)

Chrome自带恐龙小游戏的源码研究(一)

  众所周知,Chrome浏览器在网络不通的情况下,会出现一个霸王龙翻越障碍的小游戏: 技术分享

  这个游戏做得小巧精致,于是探究了一下它的源码,发现代码写得相当严谨并且富有技巧性,用来学习再好不过了。

  游戏虽然看起来简单,但也有几千行的代码量。主要包括五个构造函数:

  • 游戏逻辑控制函数Runner

  • 背景管理函数Horizon

    • 地面 (HorizonLine)
    • 云朵 (Cloud)
    • 昼夜更替 (NightMode)
    • 障碍物 (Obstacle)
  • 霸王龙函数Trex

  • 分数记录函数DistanceMeter

  • 游戏结束操作面板函数GameOverPanel

  其余的方法还包含一些对移动设备的适配、针对不同屏幕加载不同的资源 、声音的播放等等。这是游戏用到的雪碧图:

 

技术分享

  为方便研究,从简单的背景管理函数开始。首先是地面的绘制。地面绘制通过HorizonLine完成:

 1 //定义属性 2  3 HorizonLine.dimensions = { 4     WIDTH:600,    //宽600 5     HEIGHT:12,    //高12像素 6     YPOS:127    //在canvas中的位置 7 }; 8  9 var spriteDefinition = {10     HORIZON: {x: 2, y: 54}//地面在雪碧图中的位置11 };12 13 14 15 /**16 * canvas 地面将绘制到此画布上17 * spritePos 地面在雪碧图中的坐标18 */19 function HorizonLine(canvas,spritePos) {20     this.spritePos = spritePos;21     this.canvas = canvas;22     this.ctx = canvas.getContext("2d");23     this.dimensions = HorizonLine.dimensions;24 25     //在雪碧图中坐标为2和602处分别为不同的地形26     this.sourceXPos = [this.spritePos.x,this.spritePos.x + this.dimensions.WIDTH];27 28     this.xPos = []; //地面在画布中的x坐标29     this.yPos = 0;  //地面在画布中的y坐标30 31     this.bumpThreshold = 0.5;    //随机地形系数32 33     this.setSourceDimesions();34     this.draw();35 }

再来看看HorizonLine原型链中的方法:

 1 HorizonLine.prototype = { 2     setSourceDimesions:function() { 3         //地面在画布上的位置 4         this.xPos = [0,this.dimensions.WIDTH];//0,600 5         this.yPos = this.dimensions.YPOS; 6     }, 7     //随机地形 8     getRandomType:function() { 9         //返回第一段地形或者第二段地形10         return Math.random() > this.bumpThreshold ? this.dimensions.WIDTH : 0;11     },12     draw:function() {13         //使用9参数的drawImage方法14         this.ctx.drawImage(imgSprite,15             this.sourceXPos[0], this.spritePos.y,16             this.dimensions.WIDTH, this.dimensions.HEIGHT,17             this.xPos[0],this.yPos,18             this.dimensions.WIDTH,this.dimensions.HEIGHT);19 20         this.ctx.drawImage(imgSprite,21             this.sourceXPos[1], this.spritePos.y,22             this.dimensions.WIDTH, this.dimensions.HEIGHT,23             this.xPos[1],this.yPos,24             this.dimensions.WIDTH,this.dimensions.HEIGHT);25     },26     updateXPos:function(pos,increment) {27         var line1 = pos,28             line2 = pos === 0 ? 1 : 0;29 30         this.xPos[line1] -= increment;31         this.xPos[line2] = this.xPos[line1] + this.dimensions.WIDTH;32 33         //若第一段地面完全移出canvas外34         if(this.xPos[line1] <= -this.dimensions.WIDTH) {35             //则将其移动至canvas外右侧36             this.xPos[line1] += this.dimensions.WIDTH * 2;37             //同时将第二段地面移动至canvas内38             this.xPos[line2] = this.xPos[line1] - this.dimensions.WIDTH;39 40             //选择随机地形41             this.sourceXPos[line1] = this.getRandomType() + this.spritePos.x;42         }43     },44     update:function(deltaTime,speed) {45         var increment = Math.floor(speed * (FPS / 1000) * deltaTime);46 47         if(this.xPos[0] <= 0) {//交换地面一和二48             this.updateXPos(0, increment);49         } else {50             this.updateXPos(1, increment);51         }52         this.draw();53     },54     reset:function() {55         this.xPos[0] = 0;56         this.xPos[1] = this.dimensions.WIDTH;57     }58 };

原型链中的方法实现了地面的运动和随机地形。

最后测试一下这一段代码:

 1 window.onload = function () { 2     var h = new HorizonLine(canvas,spriteDefinition.HORIZON); 3     var startTime = 0; 4     (function draw(time) { 5         ctx.clearRect(0,0,600,150); 6         time = time || 0; 7         h.update(time - startTime,3); 8         startTime = time; 9         window.requestAnimationFrame(draw);10     })();11 };

运行效果:

 

<script type="text/javascript">// this.bumpThreshold ? this.dimensions.WIDTH : 0; }, draw:function() { this.ctx.drawImage(imgSprite, this.sourceXPos[0], this.spritePos.y, this.dimensions.WIDTH, this.dimensions.HEIGHT, this.xPos[0],this.yPos, this.dimensions.WIDTH,this.dimensions.HEIGHT); this.ctx.drawImage(imgSprite, this.sourceXPos[1], this.spritePos.y, this.dimensions.WIDTH, this.dimensions.HEIGHT, this.xPos[1],this.yPos, this.dimensions.WIDTH,this.dimensions.HEIGHT); }, updateXPos:function(pos,increment) { var line1 = pos, line2 = pos === 0 ? 1 : 0; this.xPos[line1] -= increment; this.xPos[line2] = this.xPos[line1] + this.dimensions.WIDTH; if(this.xPos[line1] <= -this.dimensions.WIDTH) { this.xPos[line1] += this.dimensions.WIDTH * 2; this.xPos[line2] = this.xPos[line1] - this.dimensions.WIDTH; this.sourceXPos[line1] = this.getRandomType() + this.spritePos.x; } }, update:function(deltaTime,speed) { var increment = Math.floor(speed * (FPS / 1000) * deltaTime); if(this.xPos[0] <= 0) { this.updateXPos(0, increment); } else { this.updateXPos(1, increment); } this.draw(); }, reset:function() { this.xPos[0] = 0; this.xPos[1] = this.dimensions.WIDTH; } }; window.onload = function () { var h = new HorizonLine(canvas,spriteDefinition.HORIZON); var startTime = 0; (function draw(time) { ctx.clearRect(0,0,600,150); time = time || 0; h.update(time - startTime,3); startTime = time; window.requestAnimationFrame(draw,canvas); })(); };})();// ]]></script>

这样地面的绘制及滚动就完成了。

Chrome自带恐龙小游戏的源码研究(一)