[HandTris] #7. ์๋ ํ๋ฉด์ ๋ธ๋ญ ์์์ด ๋จ๋ ์ด์ ํด๊ฒฐ - (์ ๋์์ผ๋ก ํ๋ ์จ๋ผ์ธ ์น ํ ํธ๋ฆฌ์ค ๊ฒ์ ๋ง๋ค๊ธฐ)
์น์บ ์ ์ด์ฉํ ํ ํธ๋ฆฌ์ค ๊ฒ์์ ๋ง๋ค๊ธฐ๋ก ๊ฒฐ์ฌํ์ ๋ Phaser.js์ ๊ฐ์ 2D ๊ฒ์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ ํน์ HTML5์ Canvas๋ฅผ ์ด์ฉํด์ Javascript๋ก ๊ตฌํ์ ํ ๊ฒ์ด๋ ๊ฒฐ์ ํ ํ์๊ฐ ์์๋ค. ๊ฒฐ๋ก ์ ์ผ๋ก HTML5์ Canvas๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ํ๋ค. ์๋ํ๋ฉด Canvas๋ก ํ ํธ๋ฆฌ์ค ๊ฒ์์ ๊ตฌํํ ์์ ์ฝ๋๊ฐ ๋ง์๊ณ , 2D ๊ฒ์ ํ๋ ์์ํฌ์ ์๋ฃ๊ฐ ๋งค์ฐ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ต๊ทผ์๋ ์น์์ ๊ฒ์์ ๊ตฌํํ๋ค๊ณ ํ์ ๋ HTML5๊ฐ ์๋ Unity๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์ ํ๋๊ธฐ ๋๋ฌธ์ธ ๊ฒ ๊ฐ๋ค.
Canvas์ ๊ฒ์์ ๊ตฌํํ๋ค ๋ณด๋ ์ด์ค for๋ฌธ์ผ๋ก ์ง์ฌ๊ฐํ ํํ์ ํ ํธ๋ฆฌ์ค ๋ณด๋๋ฅผ ๊ทธ๋ฆฌ๊ณ , '์์ ์น ํ๋ค, ์ ์น ํ๋ค' ํ๋ ๋ฑ์ ๋ฐ๋ณต ์์ ์ ์น์ ์์ฃผ ์์ผ์ผ ํ๋ค. ์ํฉ์ด ์ด๋ ๋ค๋ณด๋ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌํด์ค์ผ ํ๋ ๋ถ๋ถ๋ ๋ง๊ณ , ์ฝ๋๋ ์ ์ ๋ณต์กํด์ก๋ค.
์ด๋ฐ ์ํฉ์์ ์๋ ํ๋ฉด์ ์์์ด ๋จ๋ ์ด์๊ฐ ๋ฐ์ํ๋ค.
1. ์ํฉ ํ์ ๐ค
๊ฒ์์ด๋ค๋ณด๋ ๋์ผํ ๋ฒ๊ทธ ์ํฉ์ ์ฌํํ๋ ๊ฒ ์ด๋ ค์ ๋ค. ํ๋ฉด ๋ นํ๋ฅผ ํ์ฌ ์์์ ๋๋ ค๋ณด๋ฉด์ ์์์ด ์๊ธฐ๋ ์ด์์ ๋ํด์ ํ์ ํ๊ณ ์ ํ์๋ค.
2. ์์ธ ํ์
์์์ ํํ๊ฐ ๋ฒ๊ทธ ์์ธ์ ํ์ ํ๋ ๋ฐ ํฐ ๋์์ด ๋์๋ค. ์์ ์ด๋ฏธ์ง์ ๊ฐ์ด ์์์ '์ข'์์ '์ฐ'๋ก, '์'์์ '์๋'๋ก ์๊ธฐ๋ ๊ฒ์ ์ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ ์์์ ๊ทธ๋ฆฐ ๋ธ๋ญ์ด๋ , ๋ค๋ฅธ ๋ธ๋ญ์ด๋ ๊ทธ ์๋ฆฌ๋ฅผ ์ง๋๋ฉด์ ์์์ ์ง์ด๋ค! ๊ทธ๋ฆฌ๊ณ ๋ ํ ๊ฐ์ง ํน์ง์ ๊ณต๊ฒฉ์ ๋ฐ์ ํ์ ์์์ด ๊ทธ๋ ค์ง๋ค๋ ๊ฒ์ด๋ค.
3. ์์ธ
addBlockRow = () => {
const newRow = new Array(this.COL).fill("grey");
const randomIndex = Math.floor(Math.random() * this.COL);
newRow[randomIndex] = this.VACANT;
this.board.push(newRow);
this.board.shift();
this.drawBoard();
this.board_forsend.push(newRow);
this.board_forsend.shift();
};
newRow ๋ฐฐ์ด์ "grey" color๋ก fill ํ์ฌ ๊ณต๊ฒฉ์ ๋ฐ์์ผ๋ก์ ์ถ๊ฐ๋๋ ๋ธ๋ญ์ ๋ง๋ค๊ณ , ๋๋คํ๊ฒ ํ ์นธ์ ๊ณต๋ฐฑ ์์์ผ๋ก ์น ํ์ฌ ํ ์ค์ด ์์ฑ๋์ด ์๋์ผ๋ก clear๋๋ ๊ฒ์ ๋ฐฉ์งํ๋ค. ํด๋น ์ฝ๋ ์๋์ board ๋ฐฐ์ด ๋ฐ board_forsend ๋ฐฐ์ด๋ก push ๋ฐ shift ํ์ฌ ์ด๋ฅผ ๋ฐ์ํ๋ ์ฝ๋๊ฐ ์๋ค.
์ฆ, addBlockRow() ํจ์๊ฐ ํธ์ถ๋๋ฉด board_forsend ๋ฐฐ์ด์ ๊ณต๊ฒฉ ๋ธ๋ญ์ด ์ถ๊ฐ๋๋ค.
*board_forsend ๋ฐฐ์ด์ ๊ณต๊ฒฉ ๋ธ๋ญ์ ์ถ๊ฐํด์ฃผ์ด์ผ ์๋ํธ์ ๋์ ํ ํธ๋ฆฌ์ค ๋ณด๋๋ฅผ ๋ณด์ฌ์ค ๋, ๊ณต๊ฒฉ ๋ฐ์์์ ๋ณด์ฌ์ค ์ ์๋ค.
wsManagerRef.current?.subscribe(
`/user/queue/tetris/${roomCode}`,
(message: {
board: TetrisBoard;
isEnd: boolean;
isAttack: boolean;
}) => {
if (tetrisGameRef.current) {
if (message.isEnd) {
tetrisGameRef.current.gameEnd = true;
backgroundMusic.pause();
playSoundEffect("/sounds/winner.wav");
setGameResult("you WIN!");
}
if (message.isAttack) {
tetrisGameRef.current.addBlockRow();
}
tetrisGameRef.current.drawBoard2(message.board);
}
addBlockRow() ํจ์๊ฐ ํธ์ถ๋๋ ์์ ์ ์์์ ํ์ธํ ์ ์๋ค. WebSocket์ผ๋ก ์๋ฒ๋ฅผ ๊ตฌ๋ ํ๊ณ ์๊ธฐ์ call back ํจ์๋ก message๋ฅผ ์ ๋ฌ๋ฐ์ผ๋ฉด, message ๋ด์ 'isAttack' ๋ณ์๋ฅผ ํ์ธํ์ฌ true์ธ ๊ฒฝ์ฐ ๊ณต๊ฒฉ ๋ฐ๊ฒ ๋๋ค.
fill(color: string, isGhost: boolean = false) {
for (let r = 0; r < this.activeTetromino.length; r++) {
for (let c = 0; c < this.activeTetromino[r].length; c++) {
if (this.activeTetromino[r][c]) {
if (!isGhost) {
if (this.y + r >= 0 && this.x + c >= 0) {
this.game.board_forsend[this.y + r][this.x + c] = color;
}
}
this.game.drawSquare(
this.game.ctx,
this.x + c,
this.y + r,
color,
isGhost,
);
}
}
}
}
๋ง์ง๋ง์ผ๋ก board_forsend ๋ฐฐ์ด์ color ๋ฌธ์์ด์ ๋ด๋ ํจ์๋ฅผ ๋ณด๋ฉด ์์ ๊ฐ๋ค. ๋ก์ง์ '๋์ ํ ํธ๋ฆฌ์ค ๋ณด๋'์ ์์ fill ํ๋ฉด์ ์๋๋ฐฉ์๊ฒ ๋์ 'ํ ํธ๋ฆฌ์ค ๋ณด๋' ์ํ๋ผ๊ณ ์๋ ค์ค ๋ณ์์ ์์ ํ ๋นํ๋ ๊ฒ์ด๋ค.
4. ์ ๋ฆฌ
3๋ฒ์ ์์ธ์ผ๋ก ๋ฏธ๋ฃจ์ด ๋ณด์ fill ํจ์๋ก board_forsend ๋ฐฐ์ด์ color๋ฅผ ํ ๋นํ ํ addBlockRow() ํจ์๊ฐ ํธ์ถ์ด ๋๋ฉด, ํธ์ถ ์ ๋ถํฐ index๊ฐ 1์ฉ ๊ฐ์ํ๋ ๊ฒ์ด๋ค. ๋ง์ง๋ง์ผ๋ก 3ํ์ ์๋ ๋ธ๋ญ์ด ๋จ์ด์ง๋ฉด์ ๊ธฐ์กด 4ํ์ ๋ธ๋ญ์ ์ง์ฐ๊ณ ๋จ์ด์ง๋ค.
5. ์ฐํ(?)
์ ๋ฌธ์ ๋ฅผ ํ์ธํ ๊ฒ์ ํผ๋๋ฐฑ์ด ์๋ ๋ง์ง๋ง ๋ฐํ ์ ๋ ๋ฐค์ด์๋ค. ์๋น ์ ๋ก์ปฌ์์ ํผ์ ๊ฒ์์ ํ ์คํธํ๋ค๋ณด๋ ์์์ด ๊ทธ๋ ค์ง๋ ๊ฒ์ ๋์น์ฑ์ง ๋ชป ํ์๋ค. ์๊ฐ์ด ์ผ๋ง ์์๊ธฐ์ ๋ช ๊ฐ์ง ๊ฐ๋ฅํ ๋ฐฉ์ ์ค ๊ทธ๋๋ง ์ฝ๊ฒ ๊ณ ์น ์ ์๋ ๋ฐฉ์์ผ๋ก ๋จผ์ ์๋ํ์๋ค.