目錄
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 };
運行效果:
這樣地面的繪制及滾動就完成了。