diff --git a/seventh-step/index.css b/seventh-step/index.css new file mode 100644 index 0000000..85e5256 --- /dev/null +++ b/seventh-step/index.css @@ -0,0 +1,32 @@ +body { + margin: 0; + padding: 0; +} + +/*当前俄罗斯方块*/ +.activityModel { + border: 1px; + width: 19px; + height: 19px; + background: linear-gradient(70deg, indianred, white); + position: absolute; +} + +/*已经掉落的俄罗斯方块*/ +.inactiveModel { + border: 1px; + width: 19px; + height: 19px; + position: absolute; + background: linear-gradient(70deg, grey, white); +} + +/*画布*/ +.site { + position: absolute; + left: 200px; + top: 200px; + width: 200px; + height: 360px; + background-color: black; +} diff --git a/seventh-step/index.html b/seventh-step/index.html new file mode 100644 index 0000000..7c42204 --- /dev/null +++ b/seventh-step/index.html @@ -0,0 +1,13 @@ + + + + + seventh-step + + + + +
+ + + diff --git a/seventh-step/index.js b/seventh-step/index.js new file mode 100644 index 0000000..8c27b69 --- /dev/null +++ b/seventh-step/index.js @@ -0,0 +1,359 @@ +/** + * Created by llan on 2017/1/23. + */ +'use strict'; + +class Block { + constructor(params) { + this.siteSize = params.siteSize; + this.arr = params.arr; + this.BLOCK_SIZE = params.BLOCK_SIZE; + this.curLeft = params.curLeft; + this.curTop = params.curTop; + } + + /** + * 数组矩阵顺时针旋转 + * @param arr 需要旋转的数组矩阵 + * @returns {{newArr: Array, lefts: Array, tops: Array}} 返回旋转后的数组矩阵&左偏移量&上偏移量 + */ + clockwise(arr) { + let newArr = []; + for (let i = 0; i <= arr.length - 1; i++) { + let temArr = []; + for (let j = arr.length - 1; j >= 0; j--) { + temArr.push(arr[j][i]); + } + newArr.push(temArr); + } + let lefts = [], + tops = []; + this.checkArrWith1(newArr, function (i, j) { + lefts.push(j * this.BLOCK_SIZE); + tops.push(i * this.BLOCK_SIZE); + }); + return { + newArr: newArr, + lefts: lefts, + tops: tops + }; + } + + /** + * 判断二维数组为1的下标 + * @param arr 需要判断的数组矩阵 + * @param callback + */ + checkArrWith1(arr, callback) { + for (let i = 0; i <= arr.length - 1; i++) { + for (let j = 0; j <= arr.length - 1; j++) { + if (arr[i][j] === 1) { + callback.call(this, i + this.curTop, j + this.curLeft); + } + } + } + } + + /** + * 根据数组矩阵画出当前方块 + * @param i + * @param j + */ + draw(i, j) { + let activeModel = document.createElement('div'); + activeModel.className = 'activityModel'; + //控制方块出现在画布顶端中间 + activeModel.style.top = `${i * this.BLOCK_SIZE}px`; + activeModel.style.left = `${j * this.BLOCK_SIZE}px`; + //添加方块 + document.body.appendChild(activeModel); + } + + /** + * 获取当前方块能到达的边界 + * @param curLeft 当前方块left + * @param curTop 当前方块top + * @returns {*} 返回左右下边界 + */ + getInterval(curLeft, curTop) { + let inactiveModel = document.querySelectorAll('.inactiveModel'), + highest = null, + leftmost = null, + rightmost = null; + if (inactiveModel.length === 0) { + highest = this.siteSize.top + this.siteSize.height; + leftmost = this.siteSize.left - this.BLOCK_SIZE; + rightmost = this.siteSize.left + this.siteSize.width; + } else { + let tops = [], + lefts = [], + rights = []; + for (let v of inactiveModel) { + let left = parseInt(v.style.left); + let top = parseInt(v.style.top); + if (left === curLeft) { + tops.push(top); + } + if (top === curTop) { + if (left < curLeft) { + lefts.push(left); + } else if (left > curLeft) { + rights.push(left); + } + } + } + if (tops.length === 0) { + highest = this.siteSize.top + this.siteSize.height; + } else { + highest = Math.min(...tops); + } + if (lefts.length === 0) { + leftmost = this.siteSize.left - this.BLOCK_SIZE; + } else { + leftmost = Math.max(...lefts); + } + if (rights.length === 0) { + rightmost = this.siteSize.left + this.siteSize.width + } else { + rightmost = Math.min(...rights); + } + } + return { + highest: highest, + leftmost: leftmost, + rightmost: rightmost + }; + }; + + /** + * 消除砖块 + * @returns {Array} 返回每一行的元素数组,个数,高度 + */ + eliminate() { + let res = [], + inactiveModels = [...document.querySelectorAll('.inactiveModel')]; + inactiveModels.sort(function (a, b) { + return parseInt(a.style.top) - parseInt(b.style.top); + }); + for (let i = 0; i < inactiveModels.length;) { + let count = 0, + models = []; + for (let j = 0; j < inactiveModels.length; j++) { + if (inactiveModels[i].style.top === inactiveModels[j].style.top) { + count++; + models.push(inactiveModels[j]); + } + } + res.push({ + models: models, + count: count, + top: parseInt(inactiveModels[i].style.top) + }); + i += count; + } + return res; + }; + + /** + * 判断是否可以移动 + * @param arr 需要判断的矩阵数组 + * @param deform 是否需要形变 + * @param displacement 位移量 + * @returns {{canMoveRight: boolean, canMoveDown: boolean, canMoveLeft: boolean}} + * @param move + */ + canMove(arr, deform = false, displacement = 1, move = { + canMoveRight: true, + canMoveDown: true, + canMoveLeft: true + }) { + let highest = null; + this.checkArrWith1(arr, function (i, j) { + let interval = this.getInterval(j * this.BLOCK_SIZE, i * this.BLOCK_SIZE), + leftmost = interval.leftmost, + rightmost = interval.rightmost; + highest = interval.highest; + if (deform) { + if (this.BLOCK_SIZE * (j + 1) > rightmost) { + move.canMoveRight = false; + } + if (this.BLOCK_SIZE * (i + displacement) > highest) { + move.canMoveDown = false; + } + if (this.BLOCK_SIZE * (j - 1) < leftmost) { + move.canMoveLeft = false; + } + } else { + if (this.BLOCK_SIZE * (j + 1) >= rightmost) { + move.canMoveRight = false; + } + if (this.BLOCK_SIZE * (i + displacement) >= highest) { + move.canMoveDown = false; + } + if (this.BLOCK_SIZE * (j - 1) <= leftmost) { + move.canMoveLeft = false; + } + } + }); + return move; + }; + + /** + * 键盘事件 + * 上下左右分别控制方块对应移动20px + */ + move() { + document.onkeydown = (e)=> { + let activeModel = document.querySelectorAll('.activityModel'); + const key = e.keyCode; + let move, + canMoveRight, + canMoveLeft, + canMoveDown; + if (activeModel.length) { + switch (key) { + //left + case 37: + canMoveLeft = this.canMove(this.arr).canMoveLeft; + if (canMoveLeft) { + for (let v of activeModel) { + v.style.left = `${parseInt(v.style.left) - this.BLOCK_SIZE}px`; + } + this.curLeft--; + } else { + console.log('can not move left'); + } + break; + //up + case 38: + let {newArr, lefts, tops} = this.clockwise(this.arr); + move = this.canMove(newArr, true); + canMoveDown = move.canMoveDown; + canMoveRight = move.canMoveRight; + canMoveLeft = move.canMoveLeft; + if (canMoveRight && canMoveDown && canMoveLeft) { + //修改当前数组矩阵 + this.arr = newArr; + //修改当前方块偏移量 + for (let i in lefts) { + activeModel[i].style.left = `${lefts[i]}px`; + activeModel[i].style.top = `${tops[i]}px`; + } + } + break; + //right + case 39: + canMoveRight = this.canMove(this.arr).canMoveRight; + if (canMoveRight) { + for (let v of activeModel) { + v.style.left = `${parseInt(v.style.left) + this.BLOCK_SIZE}px`; + } + this.curLeft++; + } else { + console.log('can not move right'); + } + break; + //space + case 32: + canMoveDown = this.canMove(this.arr, false, 2).canMoveDown; + if (canMoveDown) { + for (let v of activeModel) { + v.style.top = `${parseInt(v.style.top) + 2 * this.BLOCK_SIZE}px` + } + this.curTop += 2; + } else { + console.log('can not move down'); + } + break; + default: + break; + } + } + } + } + + /** + * 初始化方块 + */ + init() { + this.checkArrWith1(this.arr, this.draw); + let activeModel = document.querySelectorAll('.activityModel'); + const fallDown = setTimeout(function loop() { + let canMoveDown = this.canMove(this.arr).canMoveDown; + if (canMoveDown) { + for (let v of activeModel) { + v.style.top = `${parseInt(v.style.top) + this.BLOCK_SIZE}px`; + } + this.curTop++; + setTimeout(loop.bind(this), 600); + } else { + console.log('can not move down'); + for (let i = 0; i <= activeModel.length - 1; i++) { + activeModel[i].className = 'inactiveModel'; + } + let res = this.eliminate(); + for (let i = 0; i < res.length; i++) { + let {count, models, top} = res[i]; + //判断每一行方块数量,若凑满一整行,消去 + if (count === parseInt(this.siteSize.width / this.BLOCK_SIZE)) { + for (let j = 0; j < models.length; j++) { + document.body.removeChild(models[j]); + } + let inactiveModels = document.querySelectorAll('.inactiveModel'); + for (let v of inactiveModels) { + if (parseInt(v.style.top) < top) { + v.style.top = `${parseInt(v.style.top) + this.BLOCK_SIZE}px`; + } + } + } + } + init(); + clearTimeout(fallDown); + } + }.bind(this), 600); + } +} +/** + * 初始化数据 + */ +const init = ()=> { + //传入Block的变量 + const params = { + arr: __arr__, + siteSize: __siteSize__, + BLOCK_SIZE: __BLOCK_SIZE__, + curLeft: __curLeft__, + curTop: __curTop__ + }; + //新建Block + let block = new Block(params); + block.init(); + block.move(); +}; +/** + * 浏览器加载初始化 + */ +window.onload = ()=> { + //获取画布大小&位置 + let site = document.querySelector('.site'); + let {width, height, left, top} = window.getComputedStyle(site); + let siteSize = { + width: parseInt(width), + height: parseInt(height), + left: parseInt(left), + top: parseInt(top), + }; + //方块大小 + const BLOCK_SIZE = 20; + //俄罗斯方块初始位置 + let curLeft = parseInt((siteSize.left + siteSize.width / 2) / BLOCK_SIZE); + let curTop = parseInt(siteSize.top / BLOCK_SIZE); + //方块矩阵数组 + let arr = [[1, 0], [1, 0], [1, 1]]; + window.__arr__ = arr; + window.__siteSize__ = siteSize; + window.__BLOCK_SIZE__ = BLOCK_SIZE; + window.__curLeft__ = curLeft; + window.__curTop__ = curTop; + init(); +};