闲逛github发现一个javascript原生实现的小游戏,源码写的很清晰,适合想提升水平的同窗观摩学习。读通源码后,我决定写一系列的博客来分析源码,从总体架构到具体实现细节来帮助一些想提升水平的朋友。源码地址为:https://github.com/keenwon/flappy-pigjavascript
须要提醒你们的是,个人分析模式是,先给出源码,加上注释让你们通读一遍,而后分解源码逐步分析。前端
下载了做者的源码后先看一下目录结构:java
其中做者使用了Grunt进行了打包,会使用的grunt的小伙伴一看这个目录确定一目了然,若是你历来没有使用过任何前端构建工具,别担忧,你只用关注src文件夹就能够了,打开src文件夹,内容以下:git
这就是游戏的所有组成部分了,咱们只关心具体的控制逻辑,因此直接进入js文件夹:github
var flappy = (function (self) { 'use strict';//开启严格模式,新手能够暂时忽视 var controller = self.controller,//获取控制者对象,以后详细介绍 option = self.option,//获取配置值,以后详细介绍 pig = self.pig,//获取小猪模块,以后详细介绍 pillar = self.pillar,//获取柱子模块,以后详细介绍 pos = self.position,//获取位置模块,以后详细介绍 util = self.util,//获取工具模块,以后详细介绍 $ = self.util.$;//从util.js中咱们能够看出,$方法能够经过id获取DOM元素 //主程序 self.game = {//给self对象添加game属性,该属性指向一个对象 init: function () {//game对象的init方法 var t = this;//this指向函数调用者,非特殊状况下(不使用call、apply或者直接调用),通常咱们就先认为指向了game对象,由于从后面咱们也能够看到,做者也是经过flappy.game.init()调用的。 t._isStart = false;//game有一个isStart属性,用于标识游戏是否开始,初始值为false t._isEnd = false;//game有一个isEnd属性,用于表示游戏是否结束,初始值为false t._timer = null;//game对象有一个定时器,初始化为null pig.init(t.fall, t);//调用pig模块的init方法,将game.fall方法和game对象传递过去 pillar.init();//调用pillar模块的init方法 pos.init(t.hit, t);//调用pos模块的init方法,将game.hit方法和game对象传递过去 t.addKeyListener();//将this指向game,给game对象添加键盘监听 }, addKeyListener: function () {//监听键盘事件 var t = this;//this指向函数调用者,从上面能够看到调用者是game document.onkeydown = function (e) {//监听键盘按下事件 e = e || window.event;//获取事件对象,兼容IE var currKey = e.keyCode || e.which || e.charCode;//获取按了哪个按键,兼容各家浏览器 if (currKey == 32) {//若是按下了空格 if (!t._isEnd) {//若是游戏没有结束 t.jump();//那么调用game.jump()方法 } else { window.location.reload();//若是游戏已经结束,按空格后刷新页面,从新开始 } util.preventDefaultEvent(e);//阻止事件的默认行为,具体细节在util.js中,我会在相应章节分析 } }; }, jump: function () {//这里就是game.jump()方法 var t = this;//指向game对象 if (!t._isStart) {//若是游戏没有开始 $('start').style.display = 'none';//将游戏开始界面隐藏 t._createTimer(function () {//调用game._createTimer方法,建立定时器,每二十毫秒执行一次 pig.start();//调用pig模块的start方法,让小猪开始移动,具体细节在pig.js中,我会在相应章节分析 pillar.move();//,调用pillar模块的move方法,让柱子移动,具体细节在pillar.js中,我会在相应章节分析 pos.judge();//调用pos模块的judge方法,判断位置,具体细节在position.js中,我会在相应章节分析 $('score').innerHTML = pillar.currentId + 1;//设置记分板分数 }); t._isStart = true;//设置游戏状态为已开始 } else { pig.jump();//若是游戏已经开始,那么直接调用pig.jump方法 } }, hit: function () {//game对象的hit方法 var t = this; t.over();//调用game.over方法,游戏结束 pig.hit();//调用pig模块的hit方法,具体细节在pig.js中,我会在相应章节分析 }, fall: function () {//game对象的fall方法 var t = this; t.over();//调用game.over方法,游戏结束 pig.fall();//调用pig模块的fall方法,具体细节在pig.js中,我会在相应章节分析 }, over: function () {//game对象的over方法,负责结束游戏 var t = this;//获取game对象 clearInterval(t._timer);//取消计时器 t._isEnd = true;//将标识游戏是否结束的变量设置为true $('end').style.display = 'block';//游戏结束的提示显示出来 }, _createTimer: function (fn) {//game对象的_createTimer方法,建立定时器 var t = this;//获取game对象 t._timer = setInterval(fn, option.frequency);//实现定时器,频率为配置项中的frequency属性,具体细节在option.js中,我会在相应章节介绍 } }; flappy.init = function () {//暴露接口 self.game.init();//game.init()函数中this指向game }; return self;//返回self对象,实际上也就是给本来的flappy对象加了点东西 })(flappy || {});