추억이 담긴 게임 '테트리스(TETRIS)'
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>테트리스</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="wrapper">
<div class="game-text">
<span>!게임종료!</span>
<button>다시시작</button>
</div>
<div class="score">0</div>
<div class="playground">
<ul></ul>
</div>
</div>
<script src="js/tetris.js" type="module"></script>
</body>
</html>
CSS
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
body {
height: 100%;
overflow: hidden;
}
.game-text {
display: none;
justify-content: center;
align-items: center;
flex-direction: column;
position: fixed;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
left: 0;
top: 0;
color: #fff;
font-size: 50px;
}
.game-text > button {
padding: 0.5rem 1rem;
color: #fff;
background: salmon;
border: none;
cursor: pointer;
}
.score {
text-align: center;
font-size: 36px;
margin-bottom: 2rem;
}
.playground > ul {
border: 1px solid #333;
width: 250px;
margin: 0 auto;
}
.playground > ul > li {
width: 100%;
height: 25px;
}
.playground > ul > li > ul {
display: flex;
}
.playground > ul > li > ul > li {
width: 25px;
height: 25px;
outline: 1px solid #ccc;
}
.tree {
background: #67c23a
}
.bar {
background: salmon;
}
.zee {
background: #e6a23c;
}
.elLeft {
background: #8e44ad;
}
.elRight {
background: #16a085
}
.squre {
background: #505050;
}
JS
import BLOCKS from "./blocks.js"
const playground = document.querySelector(".playground > ul");
const gameText = document.querySelector(".game-text");
const scoreDisplay = document.querySelector(".scoreDisplay");
const restartButton = document.querySelector(".game-text > button");
const GAME_ROMS = 20;
const GAME_COLS = 10;
let score = 0;
let duration = 500;
let downInterval;
let tempMovingItem;
const movingItem = {
type: "",
direction: 0,
top: 0,
left: 0,
};
init()
function init() {
tempMovingItem = { ...movingItem};
for(let i=0; i < GAME_ROMS ; i++) {
prependNewLine()
}
generateNewBlock();
}
function prependNewLine() {
const li = document.createElement("li");
const ul = document.createElement("ul");
for(let j=0; j < GAME_COLS; j++) {
const matrix = document.createElement("li");
ul.prepend(matrix);
}
li.prepend(ul)
playground.prepend(li)
}
function renderBlocks(moveType = "") {
const { type, direction, top, left } = tempMovingItem;
const movingBlocks = document.querySelectorAll(".moving");
movingBlocks.forEach(moving => {
moving.classList.remove(type, "moving");
console.log(moving)
})
BLOCKS[type][direction].some(block=>{
const x = block[0] + left;
const y = block[1] + top;
console.log(playground.childNodes[y])
const target = playground.childNodes[y] ? playground.childNodes[y].childNodes[0].childNodes[x] : null
const isAvailable = checkEmpty(target);
if (isAvailable) {
target.classList.add(type, "moving")
} else {
tempMovingItem = { ...movingItem}
if(moveType === 'retry') {
clearInterval(downInterval);
showGameoverText();
}
setTimeout(() => {
renderBlocks('retry')
if (moveType === "top") {
seizeBlock();
}
}, 0)
return true;
}
})
movingItem.left = left;
movingItem.top = top;
movingItem.direction = direction;
}
function seizeBlock() {
const movingBlocks = document.querySelectorAll(".moving");
movingBlocks.forEach(moving => {
moving.classList.remove("moving");
moving.classList.add("seized");
})
checkMatch()
}
function checkMatch() {
const childNodes = playground.childNodes;
childNodes.forEach(child => {
let matched = true;
child.children[0].childNodes.forEach(li => {
if(!li.classList.contains("seized")) {
matched = false;
}
})
if(matched) {
child.remove();
prependNewLine();
score ++;
scoreDisplay.innerText = score;
}
})
generateNewBlock()
}
function generateNewBlock() {
clearInterval(downInterval);
downInterval = setInterval(() => {
moveBlock('top',1)
}, duration)
const blockArray = Object.entries(BLOCKS);
const randomIndex = Math.floor(Math.random() * blockArray.length)
movingItem.type = blockArray[randomIndex][0];
movingItem.top = 0;
movingItem.left = 3;
movingItem.direction = 0;
tempMovingItem = { ...movingItem};
renderBlocks()
}
function checkEmpty(target) {
if( !target || target.classList.contains("seized")) {
return false;
}
return true;
}
function moveBlock(moveType, amount) {
tempMovingItem[moveType] += amount;
renderBlocks(moveType);
}
function changeDirection() {
const direction = tempMovingItem.direction;
direction === 3 ? tempMovingItem.direction = 0 : tempMovingItem.direction += 1;
renderBlocks();
}
function dropBlock() {
clearInterval(downInterval);
downInterval = setInterval(() => {
moveBlock("top",1)
}, 10)
}
function showGameoverText() {
gameText.style.display = "flex"
}
document.addEventListener("keydown", e=> {
switch(e.keyCode){
case 39:
moveBlock("left", 1);
break;
case 37:
moveBlock("left", -1);
break;
case 38:
changeDirection();
break;
case 40:
moveBlock("top", 1);
break;
case 32:
dropBlock();
break;
default:
break;
}
})
restartButton.addEventListener("click", () => {
playground.innerHTML = '';
gameText.style.display = "none";
init();
})
- 아직 약간의 오류들이 존재한다. 이 정도를 혼자 힘으로 구현할 실력이 된다면 1차적인 목표는 달성하지 않을까
- 갈 길이 멀다는 사실을 체감 중이다.
- 꾸준히 코딩 공부한지 3주째이다. 근무를 제외하고 하루도 빠지지 않았다. 요즘엔 연등2시간에 개인정비시간 1시간 더 투자하고 있다. 배움에 대한 즐거움을 수능 이후로 다시끔 느낀다.
- 더 잘하고 싶다. javascript를 집중적으로 파 볼 생각이다. 그리고 node.js 등을 건들여보겠다.
James had always been skeptical about online casinos, viewing them as little more than flashy distractions. However, a https://tortugacasino-france.com conversation with a colleague about a new blackjack platform piqued his curiosity. Intrigued by the site’s innovative approach and positive reviews, James decided to give it a try. He started with a modest deposit, not expecting much but hoping for a bit of fun.