实例化两个SnakeGame对象,一个对象使用默认的上下左右键和空格键作为方向键和暂停键,而另一个使用了,W、A、S、D 以及 Q 作为方向键和暂停键。效果如下:
嗯哼,没错,完美实现了。使用SnakeGame这个组件,创建贪吃蛇游戏就是如此的简单。下面简单介绍一下,组件的实现方式。
3贪吃蛇组件实现方式
在上一节中就提到过,没有采用过道哥拉斯的设计模式,下面给出贪吃蛇设计结构。具体的源代码,可以在后面的链接中进行下载。代码如下:
/** * Created by tjm on 8/18/2017. */ var SnakeGame = function () { /*蛇块和食物组件类*/ function SnakeBlock(row,col){ this.row=row; this.col=col; } SnakeBlock.prototype.draw = function(graphic,color,size){ graphic.fillStyle=color; graphic.fillRect(size*this.col,size*this.row,size-2,size-2); } SnakeBlock.prototype.clearDraw = function(graphic,color,size){ graphic.fillStyle=color; graphic.fillRect(size*this.col,size*this.row,size,size); } SnakeBlock.prototype.equal = function(snakeBlock){ if(snakeBlock.row==this.row && snakeBlock.col==this.col){ return true; }else{ return false; } } /*贪吃蛇组件类*/ function SnakeGame(gameScenseId, gameConfigObj) { // 私有属性 var gameScense = document.getElementById(gameScenseId); var graphic = gameScense.getContext("2d"); var count = 0; var snake; var curFood; var runId; var isMoved = false;//方向改变后,如果没有移动则方向键暂时失效。 var gameStatus = false; var curDirection = 1; var size = gameConfigObj.size || 20; var rowCount = gameConfigObj.rowCount || 30; var colCount = gameConfigObj.colCount || 30; var snakeColor = gameConfigObj.snakeColor || "green"; var foodColor = gameConfigObj.foodColor || "yellow"; var scenseColor = gameConfigObj.scenseColor || "black"; var directionKey = gameConfigObj.directionKey || [39, 40, 37, 38]; var pauseKey = gameConfigObj.pauseKey || 32; var levelCount = gameConfigObj.levelCount || 10; var curSpeed = gameConfigObj.curSpeed || 200; //公开事件 var onCountChange = gameConfigObj.onCountChange || null; //带有一个参数 var onGamePause = gameConfigObj.onGamePause || null; //带有一个参数 var onGameOver = gameConfigObj.onGameOver || null; //判断 if(gameScense.width != size*rowCount || gameScense.height != size*colCount){ throw "场景大小不等于行列大小*蛇块大小"; } //特权方法 this.startGame = startGame; this.changeGameStatus = changeGameStatus; //注册 dom 键盘事件 var preFunc = document.onkeydown; document.onkeydown = function (e) { var key = (e || event).keyCode; handleKeyInput(key); if (typeof preFunc == "function") { preFunc(e); } } //私有方法 /*初始化蛇身*/ function initSnake(){ ··· } /*绘制场景背景色*/ function initScense(){ ··· } /*产生食物*/ function genFood(){ ··· } /*吃食物*/ function eatFood(snakeHead){ ··· } /*判断游戏是否结束*/ function gameOver(){ ··· } /*蛇移动*/ function snakeMove(){ ··· } function changeSpeed(){ ··· } function handleKeyInput(key){ ··· } function initGame(){ ··· } function triggerEvent(callback,argument){ ··· } function runGame(){ ··· } function pauseGame() { ··· } function changeGameStatus(){ ··· } function startGame(){ ··· } } return SnakeGame; //最后返回一个组件构造函数 }();
上面有一个很重要的地方,就是键盘注册的代码,单独列出来分析一下。
var preFunc = document.onkeydown; document.onkeydown = function (e) { var key = (e || event).keyCode; handleKeyInput(key); if (typeof preFunc == "function") { preFunc(e); } }
该段代码的逻辑是,首先判断在 document 上是否注册了onkeydown 事件,如果注册了该事件,则保存所引用的事件处理程序,然后重置onkeydown事件程序,然后在新的事件处理程序中,调用先前的事件处理程序,这样就实现了事件触发后,调用所有监听该事件处理程序,而不是直接覆盖。
另外关于贪吃蛇的设计逻辑,可以参看我另外一篇文章,个人觉得讲的非常详细了,文章:基于控制台实现贪吃蛇游戏
3 小结