界面出现对应方块后,可自行控制其左右或快速下降的移动,上键可以实现方块形状的改变
- 调整代码结构
- 实现键盘控制方块移动
- game.js中代码
- 注意这里在SquareFactory中又写了个make函数,所以在game.js调用的时候,需要先new一个实例,否则会出现未定义的情况
- square.js中代码
- squareFactory.js中代码
- local.js代码
- script.js代码
- 实现效果
调整代码结构
首先调整代码结构,建立JS文件,如图
实现键盘控制方块移动
game.js中代码
var Game = function () {//dom元素var gameDiv;var nextDiv;// 游戏矩阵var gameData = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],];// 当前方块var cur;// 下一个方块var next;// divsvar nextDivs = [];var gameDivs = [];// 初始化divvar initDiv = function (container, data, divs) {for (var i = 0; i < data.length; i++) {var div = [];for (var j = 0; j < data[0].length; j++) {var newNode = document.createElement('div');newNode.className = 'none';newNode.style.top = (i * 20) + 'px';newNode.style.left = (j * 20) + 'px';// 建立一维数组container.appendChild(newNode);div.push(newNode);}// 把一维数组放到多维数组中divs.push(div);}}// 刷新divvar refreshDiv = function (data, divs) {for (var i = 0; i < data.length; i++) {for (var j = 0; j < data[0].length; j++) {if (data[i][j] == 0) {divs[i][j].className = 'none';} else if (data[i][j] == 1) {divs[i][j].className = 'done';} else if (data[i][j] == 2) {divs[i][j].className = 'current';}}}}// 检测点是否合法,即是否降落到最底部——pos为方块原点位置,x=cur.origin.x,y=cur.origin.y,var check = function (pos, x, y) {if (pos.x + x < 0) {// 超出上面return false;} else if (pos.x + x >= gameData.length) {// 超出下面return false;} else if (pos.y + y < 0) {// 到最左边return false;} else if (gameData[pos.x + x][pos.y + y] == 1) {// 已经有落下来的方块了return false;} else {return true;}}// 检测数据是否合法,pos为原点,data为每次下降的方块的数据,为有方块存在的数据下降操作时做准备var isValid = function (pos, data) {for (var i = 0; i < data.length; i++) {for (j = 0; j < data[0].length; j++) {if (data[i][j] != 0) {if (!check(pos, i, j)) {// 不等于0且非法return false;}}}}return true;}// 清除数据var clearData = function () {for (var i = 0; i < cur.data.length; i++) {if (check(cur.origin, i, j)) {for (var j = 0; j < cur.data[0].length; j++) {gameData[cur.origin.x + i][cur.origin.y + j] = 0;}}}}// 设置数据var setData = function () {for (var i = 0; i < cur.data.length; i++) {for (var j = 0; j < cur.data[0].length; j++) {// 先判断是否合法if (check(cur.origin, i, j)) {// 将cur.data[i][j]中的数据拷贝到gameData数组中gameData[cur.origin.x + i][cur.origin.y + j] = cur.data[i][j];}}}}// 下移设置var down = function () {// 判断是否可以下降,方法写在square中if (cur.canDown(isValid)) {clearData();cur.down();setData();refreshDiv(gameData, gameDivs);return true;} else {// 不能再向下return false;}}// 旋转设置var rotate = function () {// 判断是否可以下降,方法写在square中if (cur.canRotate(isValid)) {clearData();cur.rotate();setData();refreshDiv(gameData, gameDivs);}}// 左移设置var left = function () {// 判断是否可以下降,方法写在square中if (cur.canLeft(isValid)) {clearData();cur.left();setData();refreshDiv(gameData, gameDivs);}}// 右移设置var right = function () {// 判断是否可以下降,方法写在square中if (cur.canRight(isValid)) {clearData();cur.right();setData();refreshDiv(gameData, gameDivs);}}// 初始化 doms对象包含两个内容gameDiv、nextDivvar init = function (doms) {gameDiv = doms.gameDiv;nextDiv = doms.nextDiv;let square = new SquareFactory();cur = square.make(2, 2);next = square.make(3, 3);setData();initDiv(gameDiv, gameData, gameDivs);initDiv(nextDiv, next.data, nextDivs);// 调用封装函数,将cur.data[i][j]中的数据拷贝到gameData数组中setData();refreshDiv(gameData, gameDivs);refreshDiv(next.data, nextDivs);}// 导出API,在外部local里就可以调用这个init函数了this.init = init;this.down = down;this.left = left;this.right = right;this.rotate = rotate;this.fall = function () {// 返回false就不能再下降while (down());}
}
注意这里在SquareFactory中又写了个make函数,所以在game.js调用的时候,需要先new一个实例,否则会出现未定义的情况
square.js中代码
var Square = function () {// 方块数据this.data = [[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]];// 原点对象this.origin = {x: 0,y: 0}// 方向,即旋转中的索引this.dir = 0;
}
// 判断是否可以旋转
Square.prototype.canRotate = function (isValid) {var d = (this.dir + 1) % 4;var test = [[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]];for (var i = 0; i < this.data.length; i++) {for (var j = 0; j < this.data[0].length; j++) {test[i][j] = this.rotates[d][i][j];}}return isValid(this.origin, test);
}
Square.prototype.rotate = function (num) {if (!num) num = 1;this.dir = (this.dir + num) % 4;for (var i = 0; i < this.data.length; i++) {for (var j = 0; j < this.data[0].length; j++) {this.data[i][j] = this.rotates[this.dir][i][j];}}
}
// 判断是否可以下降
Square.prototype.canDown = function (isValid) {var test = {};test.x = this.origin.x + 1;test.y = this.origin.y;return isValid(test, this.data);
}
Square.prototype.down = function () {this.origin.x = this.origin.x + 1;
}
// 判断是否可以左移
Square.prototype.canLeft = function (isValid) {var test = {};test.x = this.origin.x;test.y = this.origin.y - 1;return isValid(test, this.data);
}
Square.prototype.left = function () {this.origin.y = this.origin.y - 1;
}
// 判断是否可以右移
Square.prototype.canRight = function (isValid) {var test = {};test.x = this.origin.x;test.y = this.origin.y + 1;return isValid(test, this.data);
}
Square.prototype.right = function () {this.origin.y = this.origin.y + 1;
}
squareFactory.js中代码
var Square1 = function () {// 调用Square方法Square.call(this);// 旋转数组,枚举可能的情况 其中每个元素都是二维数组this.rotates = [[[0, 2, 0, 0],[2, 2, 2, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 0, 0, 0],[2, 2, 0, 0],[2, 0, 0, 0],[0, 0, 0, 0]],[[2, 2, 2, 0],[0, 2, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[0, 2, 0, 0],[2, 2, 0, 0],[0, 2, 0, 0],[0, 0, 0, 0]],]
}
// 省去代码
Square1.prototype = Square.prototype;var Square2 = function () {// 调用Square方法Square.call(this);// 旋转数组,枚举可能的情况 其中每个元素都是二维数组this.rotates = [[[0, 2, 0, 0],[0, 2, 0, 0],[0, 2, 0, 0],[0, 2, 0, 0]],[[0, 0, 0, 0],[2, 2, 2, 2],[0, 0, 0, 0],[0, 0, 0, 0]],[[0, 2, 0, 0],[0, 2, 0, 0],[0, 2, 0, 0],[0, 2, 0, 0]],[[0, 0, 0, 0],[2, 2, 2, 2],[0, 0, 0, 0],[0, 0, 0, 0]],]
}
// 判断是否可以旋转
Square2.prototype = Square.prototype;var Square3 = function () {// 调用Square方法Square.call(this);// 旋转数组,枚举可能的情况 其中每个元素都是二维数组this.rotates = [[[2, 2, 2, 0],[0, 0, 2, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[0, 2, 0, 0],[0, 2, 0, 0],[2, 2, 0, 0],[0, 0, 0, 0]],[[2, 0, 0, 0],[2, 2, 2, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 2, 0, 0],[2, 0, 0, 0],[2, 0, 0, 0],[0, 0, 0, 0]],]
}
// 判断是否可以旋转
Square3.prototype = Square.prototype;var Square4 = function () {// 调用Square方法Square.call(this);// 旋转数组,枚举可能的情况 其中每个元素都是二维数组this.rotates = [[[2, 2, 2, 0],[2, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 2, 0, 0],[0, 2, 0, 0],[0, 2, 0, 0],[0, 0, 0, 0]],[[0, 0, 2, 0],[2, 2, 2, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 0, 0, 0],[2, 0, 0, 0],[2, 2, 0, 0],[0, 0, 0, 0]],]
}
// 判断是否可以旋转
Square4.prototype = Square.prototype;var Square5 = function () {// 调用Square方法Square.call(this);// 旋转数组,枚举可能的情况 其中每个元素都是二维数组this.rotates = [[[2, 2, 0, 0],[2, 2, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 2, 0, 0],[2, 2, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 2, 0, 0],[2, 2, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 2, 0, 0],[2, 2, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]],]
}
// 判断是否可以旋转
Square5.prototype = Square.prototype;var Square6 = function () {// 调用Square方法Square.call(this);// 旋转数组,枚举可能的情况 其中每个元素都是二维数组this.rotates = [[[0, 2, 2, 0],[2, 2, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 0, 0, 0],[2, 2, 0, 0],[0, 2, 0, 0],[0, 0, 0, 0]],[[0, 2, 2, 0],[2, 2, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 0, 0, 0],[2, 2, 0, 0],[0, 2, 0, 0],[0, 0, 0, 0]],]
}
// 判断是否可以旋转
Square6.prototype = Square.prototype;var Square7 = function () {// 调用Square方法Square.call(this);// 旋转数组,枚举可能的情况 其中每个元素都是二维数组this.rotates = [[[2, 2, 2, 0],[2, 2, 2, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 2, 0, 0],[2, 2, 0, 0],[2, 2, 0, 0],[0, 0, 0, 0]],[[2, 2, 2, 0],[2, 2, 2, 0],[0, 0, 0, 0],[0, 0, 0, 0]],[[2, 2, 0, 0],[2, 2, 0, 0],[2, 2, 0, 0],[0, 0, 0, 0]],]
}
// 判断是否可以旋转
Square7.prototype = Square.prototype;var SquareFactory = function () {SquareFactory.prototype.make = function (index, dir) {var s;index = index + 1;switch (index) {case 1:s = new Square1();break;case 2:s = new Square2();break;case 3:s = new Square3();break;case 4:s = new Square4();break;case 5:s = new Square5();break;case 6:s = new Square6();break;case 7:s = new Square7();break;default:break;}// 定义原点s.origin.x = 0;s.origin.y = 3;s.rotate(dir);return s;}
}
local.js代码
var Local = function () {// 游戏对象var game;// 绑定键盘事件var bindKeyEvent = function () {document.onkeydown = function (e) {if (e.keyCode == 38) {// 向上game.rotate();} else if (e.keyCode == 39) {// 向右game.right();} else if (e.keyCode == 40) {// 向下game.down();} else if (e.keyCode == 37) {// 向左game.left();} else if (e.keyCode == 32) {// 空格键game.fall();}}}// 开始var start = function () {var doms = {gameDiv: document.getElementById('game'),nextDiv: document.getElementById('next')}game = new Game();game.init(doms);bindKeyEvent();}// 导出APIthis.start = start;
}
script.js代码
// 创建local对象并调用var local = new Local();local.start();