目录
Chrome自带恐龙小游戏的源码研究(一)——绘制地面
Chrome自带恐龙小游戏的源码研究(二)——绘制云朵
Chrome自带恐龙小游戏的源码研究(三)——昼夜交替
Chrome自带恐龙小游戏的源码研究(四)——绘制障碍物
Chrome自带恐龙小游戏的源码研究(五)——绘制霸王龙
Chrome自带恐龙小游戏的源码研究(六)——跳跃
Chrome自带恐龙小游戏的源码研究(七)——碰撞检测
Chrome自带恐龙小游戏的源码研究(完)——游戏高分与其它要素
众所周知,Chrome浏览器在网络不通的情况下,会出现一个霸王龙翻越障碍的小游戏:
这个游戏做得小巧精致,于是探究了一下它的源码,发现代码写得相当严谨并且富有技巧性,用来学习再好不过了。
游戏虽然看起来简单,但也有几千行的代码量。主要包括五个构造函数:
-
游戏逻辑控制函数Runner
-
背景管理函数Horizon
- 地面 (HorizonLine)
- 云朵 (Cloud)
- 昼夜更替 (NightMode)
- 障碍物 (Obstacle)
-
霸王龙函数Trex
-
分数记录函数DistanceMeter
-
游戏结束操作面板函数GameOverPanel
其余的方法还包含一些对移动设备的适配、针对不同屏幕加载不同的资源 、声音的播放等等。这是游戏用到的雪碧图:
为方便研究,从简单的背景管理函数开始。首先是地面的绘制。地面绘制通过HorizonLine完成:
1 //定义属性2 3 HorizonLine.dimensions = {4 WIDTH:600, //宽6005 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,6005 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 };
运行效果:
这样地面的绘制及滚动就完成了。