From b992e21b953c73274e525a3052cec6b24ac9f9f6 Mon Sep 17 00:00:00 2001 From: fpdjsns Date: Wed, 29 Apr 2020 19:34:02 +0900 Subject: [PATCH] #7 change number of next block 1 to 3 --- Tetris/js/canvas.js | 2 +- Tetris/js/constants.js | 6 +- Tetris/js/gameAlgorithm.js | 39 +-- Tetris/js/main.js | 516 ------------------------------------- Tetris/js/nextBlock.js | 25 ++ Tetris/main.html | 6 +- 6 files changed, 52 insertions(+), 542 deletions(-) delete mode 100644 Tetris/js/main.js create mode 100644 Tetris/js/nextBlock.js diff --git a/Tetris/js/canvas.js b/Tetris/js/canvas.js index 5ee637d..5ec5535 100644 --- a/Tetris/js/canvas.js +++ b/Tetris/js/canvas.js @@ -8,7 +8,7 @@ if (canvas.getContext) { var ctxNextBlock = canvasNextBlock.getContext("2d"); canvasNextBlock.width = BIG_BLOCK_SIZE; - canvasNextBlock.height = BIG_BLOCK_SIZE; + canvasNextBlock.height = BIG_BLOCK_SIZE * NEXT_BLOCK_SIZE; } else { console.log("browser not supported canvas"); } \ No newline at end of file diff --git a/Tetris/js/constants.js b/Tetris/js/constants.js index 8cdc1ac..e7209f6 100644 --- a/Tetris/js/constants.js +++ b/Tetris/js/constants.js @@ -1,10 +1,14 @@ var canvas = document.getElementById("game"); var canvasNextBlock = document.getElementById("nextBlock"); +const BLOCK_GAP = 1; + const SMALL_BLOCK_NUM = 4; const SMALL_BLOCK_SIZE = 20; const BIG_BLOCK_SIZE = SMALL_BLOCK_SIZE * SMALL_BLOCK_NUM; +const NEXT_BLOCK_SIZE = 3; + const GAME_SCREEN_WIDTH_NUM = 10; const GAME_SCREEN_HEIGHT_NUM = 20; const GAME_SCREEN_WIDTH = GAME_SCREEN_WIDTH_NUM * SMALL_BLOCK_SIZE; @@ -27,5 +31,3 @@ const NONE_DUPLICATED = 0; const LEFT_DUPLICATED = 1; const RIGHT_DUPLICATED = 2; const EITHER_DUPLICATED = 3; - -const BLOCK_GAP = 1; diff --git a/Tetris/js/gameAlgorithm.js b/Tetris/js/gameAlgorithm.js index 0265c2e..9116a73 100644 --- a/Tetris/js/gameAlgorithm.js +++ b/Tetris/js/gameAlgorithm.js @@ -1,5 +1,5 @@ var nowBlock; -var nextBlockType = Math.floor(Math.random() * blockType.length); +var nextBlockTypes = new NextBlock(NEXT_BLOCK_SIZE); var gameScreenArray = new Array(GAME_SCREEN_HEIGHT_NUM) .fill(-1) .map(row => new Array(GAME_SCREEN_WIDTH_NUM).fill(-1)); @@ -9,33 +9,36 @@ setInterval(function() { }, SPEED); var drawNewBlock = function() { - nowBlock = new Block(nextBlockType, BEGIN_X, BEGIN_Y); + nowBlock = new Block(nextBlockTypes.pop(), BEGIN_X, BEGIN_Y); if (nowBlock.isBottom(BEGIN_X, BEGIN_Y)) { gameEnd(); } nowBlock.drawDown(BEGIN_X, BEGIN_Y); - nextBlockType = Math.floor(Math.random() * blockType.length); - drawNextBlock(); + drawNextBlocks(); }; -var drawNextBlock = function() { - var nextBlock = blockType[nextBlockType]; +var drawNextBlocks = function() { + var nextBlocks = nextBlockTypes.toArray(); var x = 0; var y = 0; - for (var i = 0; i < SMALL_BLOCK_NUM; i++) { - for (var j = 0; j < SMALL_BLOCK_NUM; j++) { - if (nextBlock.shape[0][i][j] == 1) { - ctxNextBlock.fillStyle = nextBlock.color; - } else { - ctxNextBlock.fillStyle = "white"; + for (var k = 0; k < NEXT_BLOCK_SIZE; k++) { + var nextBlock = blockType[nextBlocks[k]]; + for (var i = 0; i < SMALL_BLOCK_NUM; i++) { + for (var j = 0; j < SMALL_BLOCK_NUM; j++) { + if (nextBlock.shape[0][i][j] == 1) { + ctxNextBlock.fillStyle = nextBlock.color; + } else { + ctxNextBlock.fillStyle = "white"; + } + ctxNextBlock.fillRect( + j * SMALL_BLOCK_SIZE + x + BLOCK_GAP, + i * SMALL_BLOCK_SIZE + y + BLOCK_GAP, + SMALL_BLOCK_SIZE - BLOCK_GAP, + SMALL_BLOCK_SIZE - BLOCK_GAP + ); } - ctxNextBlock.fillRect( - (x + j) * SMALL_BLOCK_SIZE + BLOCK_GAP, - (y + i) * SMALL_BLOCK_SIZE + BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP - ); } + y += BIG_BLOCK_SIZE; } }; diff --git a/Tetris/js/main.js b/Tetris/js/main.js deleted file mode 100644 index a361c83..0000000 --- a/Tetris/js/main.js +++ /dev/null @@ -1,516 +0,0 @@ -const blockType = new Map([ - ['O', { - name: 'O', - color: "skyblue", - shape: [[[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]]] - }], - ['S', { - name: 'S', - color: "gray", - shape: [ - [[0, 0, 0, 0], [0, 0, 1, 1], [0, 1, 1, 0], [0, 0, 0, 0]], - [[0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]] - ] - }], - ['Z', { - name: 'Z', - color: "purple", - shape: [ - [[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 1, 1], [0, 0, 0, 0]], - [[0, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]] - ] - }], - ['I', { - name: 'I', - color: "darkred", - shape: [ - [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]] - ] - }], - ['T', { - name: 'T', - color: "#FFD300", - shape: [ - [[0, 0, 0, 0], [0, 1, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]], - [[0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]], - [[0, 0, 1, 0], [0, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 1, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]] - ] - }], - ['L', { - name: 'L', - color: "green", - shape: [ - [[0, 0, 0, 0], [0, 1, 1, 1], [0, 1, 0, 0], [0, 0, 0, 0]], - [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 0, 0]], - [[0, 0, 0, 1], [0, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]] - ] - }], - ['J', { - name: 'J', - color: "blue", - shape: [ - [[0, 0, 0, 0], [0, 1, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]], - [[0, 0, 1, 1], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]], - [[0, 1, 0, 0], [0, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 1, 0], [0, 0, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]] - ] - }] -]); - -var blockTypeArray = Array.from(blockType.keys()); - -var nowBlock; // Block -var nextBlockType; // blockType -var keepBlockType; // blockType - -var canvas = document.getElementById("game"); -var canvasNextBlock = document.getElementById("nextBlock"); -var canvasKeepBlock = document.getElementById("keepBlock"); - -const SMALL_BLOCK_NUM = 4; -const SMALL_BLOCK_SIZE = 20; -const BIG_BLOCK_SIZE = SMALL_BLOCK_SIZE * SMALL_BLOCK_NUM; - -const GAME_SCREEN_WIDTH_NUM = 10; -const GAME_SCREEN_HEIGHT_NUM = 20; -const GAME_SCREEN_WIDTH = GAME_SCREEN_WIDTH_NUM * SMALL_BLOCK_SIZE; -const GAME_SCREEN_HEIGHT = GAME_SCREEN_HEIGHT_NUM * SMALL_BLOCK_SIZE; - -const GAME_SCREEN_LEFT = canvas.clientLeft; -const GAME_SCREEN_RIGHT = canvas.clientLeft + GAME_SCREEN_WIDTH; -const GAME_SCREEN_TOP = canvas.clientTop; -const GAME_SCREEN_BOTTOM = canvas.clientTop + GAME_SCREEN_HEIGHT; - -const WAIT_NEXTBLOCK_TIME = 1000; - -const NOW_DELETE = -2; - -const BEGIN_X = GAME_SCREEN_LEFT + GAME_SCREEN_WIDTH_NUM / 2 - 4 / 2; -const BEGIN_Y = GAME_SCREEN_TOP; -const SPEED = 1000; - -const NONE_DUPLICATED = 0; -const LEFT_DUPLICATED = 1; -const RIGHT_DUPLICATED = 2; -const EITHER_DUPLICATED = 3; - -const BLOCK_GAP = 1; - -const LINE_COLOR = "black"; - -var gameScreenArray = new Array(GAME_SCREEN_HEIGHT_NUM) - .fill(-1) - .map(row => new Array(GAME_SCREEN_WIDTH_NUM).fill(-1)); - -if (canvas.getContext) { - var ctx = canvas.getContext("2d"); - canvas.width = GAME_SCREEN_WIDTH + BLOCK_GAP; - canvas.height = GAME_SCREEN_HEIGHT + BLOCK_GAP; - - var ctxNextBlock = canvasNextBlock.getContext("2d"); - canvasNextBlock.width = BIG_BLOCK_SIZE; - canvasNextBlock.height = BIG_BLOCK_SIZE; - - var ctxKeepBlock = canvasKeepBlock.getContext("2d"); - canvasKeepBlock.width = BIG_BLOCK_SIZE; - canvasKeepBlock.height = BIG_BLOCK_SIZE; -} else { - console.log("browser not supported canvas"); -} - -$(window).load(function() { - console.log("load"); - setNextRandomBlockType(); - drawWhiteLineOnBackground(); - drawNewBlock(); -}); - -setInterval(function() { - nowBlock.drawDown(nowBlock.x, nowBlock.y + 1); -}, SPEED); - -var drawWhiteLineOnBackground = function() { - ctx.fillStyle = LINE_COLOR; - for (var i = 0; i <= GAME_SCREEN_WIDTH_NUM; i++) { - ctx.fillRect( - i * SMALL_BLOCK_SIZE, - 0, - BLOCK_GAP, - GAME_SCREEN_HEIGHT - ); - } - for (var i = 0; i <= GAME_SCREEN_HEIGHT_NUM; i++) { - ctx.fillRect( - 0, - i * SMALL_BLOCK_SIZE, - GAME_SCREEN_WIDTH, - BLOCK_GAP - ); - } -} - -var drawNewBlock = function() { - nowBlock = new Block(nextBlockType, BEGIN_X, BEGIN_Y); - if (nowBlock.isBottom(BEGIN_X, BEGIN_Y)) { - gameEnd(); - } - nowBlock.drawDown(BEGIN_X, BEGIN_Y); - setNextRandomBlockType(); - drawNextBlock(); -}; - -var drawNextBlock = function() { - var nextBlock = nextBlockType; - var x = 0; - var y = 0; - for (var i = 0; i < SMALL_BLOCK_NUM; i++) { - for (var j = 0; j < SMALL_BLOCK_NUM; j++) { - if (nextBlock.shape[0][i][j] == 1) { - ctxNextBlock.fillStyle = nextBlock.color; - } else { - ctxNextBlock.fillStyle = "white"; - } - ctxNextBlock.fillRect( - (x + j) * SMALL_BLOCK_SIZE + BLOCK_GAP, - (y + i) * SMALL_BLOCK_SIZE + BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP - ); - } - } -}; - -var drawKeepBlock = function() { - var keepBlock = keepBlockType; - if(!keepBlock) return; - - var x = 0; - var y = 0; - for (var i = 0; i < SMALL_BLOCK_NUM; i++) { - for (var j = 0; j < SMALL_BLOCK_NUM; j++) { - if (keepBlock.shape[0][i][j] == 1) { - ctxKeepBlock.fillStyle = keepBlock.color; - } else { - ctxKeepBlock.fillStyle = "white"; - } - ctxKeepBlock.fillRect( - (x + j) * SMALL_BLOCK_SIZE + BLOCK_GAP, - (y + i) * SMALL_BLOCK_SIZE + BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP - ); - } - } -}; - -// sy ~ se row에서 지워질 수 있는 행 체크 & 지우기 -// TODO test -var checkRowsAndErase = function(sy, ey) { - var isEraseAnything = false; - for (var i = sy; i <= ey; i++) { - if (canEraseRow(i)) { - eraseRow(i); - isEraseAnything = true; - } - } - if (isEraseAnything) { - rearrange(); - } -}; - -var canEraseRow = function(row) { - for (var j = 0; j < GAME_SCREEN_WIDTH_NUM; j++) { - if (gameScreenArray[row][j] == -1) { - return false; - } - } - return true; -}; -var eraseRow = function(row) { - for (var j = 0; j < GAME_SCREEN_WIDTH_NUM; j++) { - eraseOneBlock(row, j); - gameScreenArray[row][j] = NOW_DELETE; - } -}; - -var eraseOneBlock = function(x, y) { - ctx.clearRect( - x * SMALL_BLOCK_SIZE + BLOCK_GAP, - y * SMALL_BLOCK_SIZE + BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP - ); -}; - -var drawOneBlock = function(x, y, color) { - ctx.fillStyle = color; - ctx.fillRect( - x * SMALL_BLOCK_SIZE + BLOCK_GAP, - y * SMALL_BLOCK_SIZE + BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP, - SMALL_BLOCK_SIZE - BLOCK_GAP - ); -}; - -var rearrange = function() { - for (var j = 0; j < GAME_SCREEN_WIDTH_NUM; j++) { - // from bottom - var deleteBlockNum = 0; - for (var i = GAME_SCREEN_HEIGHT_NUM - 1; i >= 0; i--) { - if (gameScreenArray[i][j] == -1) continue; - if (gameScreenArray[i][j] == NOW_DELETE) { - gameScreenArray[i][j] = -1; - eraseOneBlock(j, i); - deleteBlockNum++; - } else { - var key = gameScreenArray[i][j]; - eraseOneBlock(j, i); - gameScreenArray[i][j] = -1; - drawOneBlock(j, i + deleteBlockNum, getBlockTypeByKey(key).color); - gameScreenArray[i + deleteBlockNum][j] = key; - } - } - - } -}; - -var drawBelow = function(block) { - console.log("below"); - var x = block.x; - var y = block.y; - block.eraseBeforeBlock(); - while (!block.isBottom(x, y + 1)) { - y = y + 1; - } - - block.drawBlock(x, y); - setBlockInGameScreen(block); - checkRowsAndErase( - y, - Math.min(GAME_SCREEN_HEIGHT_NUM - 1, y + SMALL_BLOCK_NUM - 1) - ); - drawNewBlock(); -}; - -var gameEnd = function() { - alert("game over!"); -}; - -var setBlockInGameScreen = function(block) { - for (var i = 0; i < SMALL_BLOCK_NUM; i++) { - for (var j = 0; j < SMALL_BLOCK_NUM; j++) { - if (block.shape[j][i] == 1) { - gameScreenArray[block.y + j][block.x + i] = block.type.name; - } - } - } -}; - -const keepOrLoadBlock = function() { - // #1 - if(nowBlock.isLoaded) return false; - - nowBlock.eraseBeforeBlock(); - const willKeepType = nowBlock.type; - // #2 - if(keepBlockType) { - nowBlock = new Block(keepBlockType, BEGIN_X, BEGIN_Y); - nowBlock.isLoaded = true; - } - else { // #3 - nowBlock = new Block(nextBlockType, BEGIN_X, BEGIN_Y); - setNextRandomBlockType(); - } - - nowBlock.drawDown(BEGIN_X, BEGIN_Y); - keepBlockType = willKeepType; - if (nowBlock.isBottom(BEGIN_X, BEGIN_Y)) { - gameEnd(); - } - drawNextBlock(); - drawKeepBlock(); - - return true; -} - -let getBlockTypeByKey = function(blockKey) { - return blockType.get(blockKey); -} - -let getBlockTypeByIndex = function(blockIndex) { - return getBlockTypeByKey(blockTypeArray[blockIndex]); -} - -let getRandomBlockType = function() { - return getBlockTypeByIndex(Math.floor(Math.random() * blockType.size)); -} - -let setNextRandomBlockType = function() { - nextBlockType = getRandomBlockType(); -} - -/** - * - * @param {*} blockType blockType - * @param {*} x block의 x 좌표 - * @param {*} y block의 y 좌표 - */ -function Block(blockType, x, y) { - this.type = blockType; - this.shapeIndex = 0; - this.shape = this.type.shape[this.shapeIndex]; - this.x = x; - this.y = y; - this.isLoaded = false; - - this.drawLeftOrRight = function(nx, ny) { - if ( - this.isDuplicatedBlockOrOutOfGameScreen(nx, ny) != NONE_DUPLICATED - ) { - console.log("duplicated!"); - } else { - this.eraseBeforeBlock(); - this.drawBlock(nx, ny); - } - }; - - this.drawDown = function(nx, ny) { - if (this.isBottom(nx, ny)) { - setBlockInGameScreen(this); - - //한 줄 지울 수 있는지 체크 - checkRowsAndErase( - this.y, - Math.min( - GAME_SCREEN_HEIGHT_NUM - 1, - this.y + SMALL_BLOCK_NUM - 1 - ) - ); - setTimeout(drawNewBlock(), WAIT_NEXTBLOCK_TIME); - } else { - this.eraseBeforeBlock(); - this.drawBlock(nx, ny); - } - }; - - this.eraseBeforeBlock = function() { - for (var i = 0; i < SMALL_BLOCK_NUM; i++) { - for (var j = 0; j < SMALL_BLOCK_NUM; j++) { - if (this.shape[i][j] == 1) { - eraseOneBlock(this.x + j, this.y + i); - } - } - } - }; - - this.drawBlock = function(x, y) { - // Change colors just before drawing to avoid affecting the previous or next block color. - ctx.fillStyle = this.type.color; - for (var i = 0; i < SMALL_BLOCK_NUM; i++) { - for (var j = 0; j < SMALL_BLOCK_NUM; j++) { - if (this.shape[i][j] == 1) { - drawOneBlock(x + j, y + i, this.type); - } - } - } - - this.x = x; - this.y = y; - }; - - this.isDuplicatedBlockOrOutOfGameScreen = function(x, y) { - for (var i = 0; i < SMALL_BLOCK_NUM; i++) { - for (var j = 0; j < SMALL_BLOCK_NUM; j++) { - var nx = x + i; - var ny = y + j; - if (this.shape[j][i] == 0) continue; - - // out of game screen - if (nx < 0) { - return LEFT_DUPLICATED; - } - if (GAME_SCREEN_WIDTH_NUM < nx) { - return RIGHT_DUPLICATED; - } - // duplicated another block - if (gameScreenArray[ny][nx] != -1) { - return EITHER_DUPLICATED; - } - } - } - return NONE_DUPLICATED; - }; - - this.isBottom = function(x, y) { - for (var i = 0; i < SMALL_BLOCK_NUM; i++) { - for (var j = 0; j < SMALL_BLOCK_NUM; j++) { - var nx = x + i; - var ny = y + j; - if (this.shape[j][i] == 0) continue; - - if (GAME_SCREEN_HEIGHT_NUM <= ny) return true; - if (gameScreenArray[ny][nx] != -1) return true; - } - } - return false; - }; - - this.rotation = function() { - this.eraseBeforeBlock(); - this.shapeIndex = (this.shapeIndex + 1) % this.type.shape.length; - this.shape = this.type.shape[this.shapeIndex]; - var checkDuplicated = this.isDuplicatedBlockOrOutOfGameScreen( - this.x, - this.y - ); - if (checkDuplicated != NONE_DUPLICATED) { - var moveIndex = 0; - if ( - checkDuplicated == LEFT_DUPLICATED || - checkDuplicated == EITHER_DUPLICATED - ) { - for (var i = 1; i < SMALL_BLOCK_NUM; i++) { - if ( - this.isDuplicatedBlockOrOutOfGameScreen( - this.x + i, - this.y - ) == NONE_DUPLICATED - ) { - moveIndex = i; - break; - } - } - } - if ( - checkDuplicated == RIGHT_DUPLICATED || - checkDuplicated == EITHER_DUPLICATED - ) { - for (var i = 1; i < SMALL_BLOCK_NUM; i++) { - if ( - this.isDuplicatedBlockOrOutOfGameScreen( - this.x - i, - this.y - ) == NONE_DUPLICATED - ) { - moveIndex = -i; - break; - } - } - } - - // 움직여도 안되는 경우 - if (moveIndex == 0) { - this.shapeIndex = - (this.shapeIndex + this.type.shape.length - 1) % - this.type.shape.length; - this.shape = this.type.shape[this.shapeIndex]; - } else { - this.x += moveIndex; - } - } - this.drawBlock(this.x, this.y); - }; -} diff --git a/Tetris/js/nextBlock.js b/Tetris/js/nextBlock.js new file mode 100644 index 0000000..6a5d0db --- /dev/null +++ b/Tetris/js/nextBlock.js @@ -0,0 +1,25 @@ +class NextBlock { + constructor(size) { + this.typesQ = []; + for(var i = 0; i + - - test1 - test2 - test3 - test4 \ No newline at end of file