🗃️javascript/프로젝트
(클론코딩)테트리스(2)
하얀성
2022. 12. 9. 17:31
//DOM
const playground = document.querySelector(".playground > ul");
//Setting
const GAME_ROWS = 20;
const GAME_COLS = 10;
//variables
let score = 0;
let duration = 500;
let downInterval;
let tempMovingItem;
const BLOCKS = {
tree: [
[[2,1],[0,1],[1,0],[1,1]],
[],
[],
[],
]
}
const movingItem = {
type:"tree",
direction: 0,
top: 0,
left: 3,
};
init()
//functions
function init() {
tempMovingItem = {...movingItem}; // movingItem의 실제 값들만 가져온다.
for(let i=0; i<GAME_ROWS; i++) {
prependNewLine();
}
renderBlocks()
}
function prependNewLine(){ //20번 반복됨.
const li = document.createElement("li"); // list 의 약자, ul의 요소.
const ul = document.createElement("ul"); //unordered list의 약자. li를 하나라도 포함해야됨.
for(let j=0; j<10; j++) {
const matrix = document.createElement("li");
ul.prepend(matrix); // li 10개 만든거 ul에 다 붙여
}
li.prepend(ul); //li 10개 만든거를 붙인, ul 하나를 li에 붙여
playground.prepend(li); // li 10개 딸린 ul로 접착된 li 한개 붙여.(playground가 아직 배열 요소가 4개라서... 20번 반복해도 4개 나옴.)
}
function renderBlocks() {
const { type, direction, top, left } = tempMovingItem; // 타입 설정, 이동해 있는 현재 위치값 4개가 저장됨.
const movingBlocks = document.querySelectorAll(".moving"); // SelectorAll를 통해서 moving클래스를 가진 모든 요소를 불러옴.
movingBlocks.forEach(moving=>{ // 불러온 moving이라는 것을 가진 요소들에 moving 매개변수로 거기 있는 type 값과 "moving"값 제거(새 값에 moving클래스 부여하기 전, moving클래스를 가진 모든 값들)
// 이전 moving 싹다 모아서 클래스 제거부터 하고 나서, 밑에서 새로 이동한 값에도 type과 moving 클래스 값 부여. 그래서 여기서 출력 명령해도 아직 새것들은 안준상태라 안뜸.단, 명령 끝나면 부여는 되있지)
moving.classList.remove(type, "moving"); // 불러들인 moving요소 가진 것들 중 4개의 실질값([,],[,],[,],[,])의 type,moving 빼곤 다 삭제
})
BLOCKS[type][direction].forEach(block => { // block은 forEach로 훑은 요소 하나 하나를 끄집어내서 그 요소에 함수짓해서, 저장하는 매개변수.
// BLOCKS의 [][] 배열의 몇번째 값은 x번째 배열임. 0번째의 값 [0,0], 1번째의 값 [0, 1].....이런 식으로 구성되있음 이걸 foreach가 요소 하나씩 건드는것.
const x = block[0] + left; // x는 ul안에 들어 있는 li의 값 -> 몇번째 줄 안의 몇번째 li인지를 알려주는 값.
const y = block[1] + top; // y는 li의 row값 -> 몇번째 줄인지 알려주는 값.
const target = playground.childNodes[y] ? playground.childNodes[y].childNodes[0].childNodes[x] : null; // target의 범위는 y값이 허락되는 부분까지!
const isAvailable = checkEmpty(target); // target 검사결과 저장
if(isAvailable){ // y범위 안
target.classList.add(type, "moving") // target에 클래스 속성값들추가(type으로 tree 타입부여 함. tree타입은 css에 .tree로 지정해둠. moving도 부여해서 moving을 통해 행동제어 가능. )
}else{// y범위 밖
tempMovingItem = {...movingItem} // 넘어가면 못넘어가게끔 바로 이전 값으로 되돌림.(색칠 명령 못받았으니, 그만큼 색칠된 공간 갯수가 줄어듬)
setTimeout(()=>{ // 잠시 renderBlocks를 빼놨다가 실행
renderBlocks();
},0) // 0은 몇초간 멈출 건가 물어보는 setTimeout메서드의 고유 요소임.
// renderBlocks() tempMovingItem으로 원상복구 시키고서 그것을 다시 색칠하는 것으로 끝내려했는데... 재귀함수라서 첫 renderblock()의 하위의 renderblock()으로 독단적 행위가 이어지면서 결국 밑도끝도없이 나가지게됨. 그래서 setTimOut메서드로 하위에서 빠져나와서 동등한 위치에서 다시 실행하게 함. 그래서 저 tempMoving을 무시하지 않은 덕에 되돌리고, 그 값에만 renderBlock() 적용이 가능해짐.
}
})
movingItem.left = left; // 값들 계속 증가된것들 저장하는 공간.
movingItem.top = top;
movingItem.direction = direction;
}
function checkEmpty(target){
if(!target){
return false;
}
return true;
}
function moveBlock(moveType, amount){ // moveType은 tempMoving을 통해 rendering함.
tempMovingItem[moveType] += amount; // tempmoving 안의 moveType인 top, left 값을 바꿔줌. 실질적 현재 이동한 값들 4개 보유.
renderBlocks()
}
//event handling (이 event 발생 전에는 )
document.addEventListener("keydown", e=> { // 키보드의 동작을 인식하는 함수
switch(e.keyCode){
case 39:
moveBlock("left", 1); // 0.0에서 시작했으니, left라는 변수에 1을 저장해서, 1만큼 오른쪽이동
break;
case 37:
moveBlock("left", -1) //0.0에서 시작했으니, left라는 변수에 -1을 저장해서, -1만큼 왼쪽이동
break;
case 40:
moveBlock("top", 1); ㅇ
break;
default:
break;
}
// console.log(e)
})
이해되는 부분까지만...
옆으로 나가지 않게끔 만들어줌. 근데 옆으로 나가는 걸 막아주는 기능구현 부분 코드가 이해가 안된다.
-> 낮에 이해가 안됬는데 밤에 곰곰히 생각해보고 찾아보니 이해가 됨
<몰랐던 부분>
1.setTimeout 메서드(() => {}, 시간)
시간이 흐른 뒤에 {}를 실행해라.
2.() => {}의 의미는 ()안의 변수를 {}의 매개변수로 사용한다는 뜻이다.
method( ){
}
이것과 동일함. 그런데 복잡할 때 더 편하게 설정가능해져서 사용함..
3. function이 붙지 않은 새로운 메서드는 내가 모르는 고유 메서드이니.. 바로 인터넷에 찾아보도록하자.
<느낀점>
진도는 더딘데 확실히 많이 배운다.
js 기초강의 들어보면 이해가 확 와닿는다.
일단 cs든 코테든.. 프로젝트든 셋다 제대로 안되는 상황이니... 우선 지금하는 프로젝트에만 집중해야겠단 생각이다.
cs가 쉽더라도 나에겐 아직 어렵다...