우찬쓰 개발블로그

자바스크립트로 웹 테트리스 만들기(4) 본문

테트리스 개발기

자바스크립트로 웹 테트리스 만들기(4)

이우찬 2021. 3. 27. 22:43
반응형

고지가 눈앞에 보이니, 게임 시작부터 게임 오버까지 만들고 싶어졌습니다!

 

자 그럼 완성된 줄을 지우는 로직부터 시작해봅시다.

 

removeCompletedLine(lineCount) {
  let stackedBlockArray = this.stackedBlock.blockArray;
  for (let y = 0; y < heightBlockCount; y++) {
    let isCompletedLine = true;
    for (let x = 0; x < widthBlockCount; x++) {
      if (!stackedBlockArray[x][y]) {
        isCompletedLine = false;
        break;
      }
    }
    if (isCompletedLine) {
      this.removeLine(y);
      return this.removeCompletedLine(lineCount + 1);
    }
  }
  return lineCount;
}

removeLine(removeY) {
  let stackedBlockArray = this.stackedBlock.blockArray;
  for (let y = removeY; y > 0; y--) {
    for (let x = 0; x < widthBlockCount; x++) {
      stackedBlockArray[x][y] = stackedBlockArray[x][y - 1];
    }
  }
}

 

쌓인 블럭에서 완성된 줄을 지우는 로직을 재귀로 넣어줍니다.

맨 위부터 검사하여 완성된 줄이 있으면 한 줄을 지우고 내려준다음 다시 같은 함수를 호출합니다.

최종적으로 더이상 지울 줄이 없으면 총 카운트를 반환하여 줍니다.(스코어 가산점을 위해)

 

 그리고 맨 윗줄까지 채워지면 게임오버가 되는 로직도 넣어봅니다.

 

checkIsGameOver(stackedBlocks) {
  for (let x = 0; x < widthBlockCount; x++) {
    if (stackedBlocks[x][1]) {
      return true;
    }
  }
  return false;
}

 

그리고 속도가 항상 같으면 게임이 끝나지 않을테니, 난이도 조절을 위해 속도가 빨라지는 로직도 넣어봅니다.

 

let currentDifficulty = 0;
let increaseSpeedPerDifficulty = 0.985;

function levelUp() {
  currentDifficulty++;
  levelText.textContent = `speed : ${currentDifficulty}`;
  clearInterval(timeId);
  timeId = setInterval(
    () => gameScreen.flowGravity(),
    timePerLine * Math.pow(increaseSpeedPerDifficulty, currentDifficulty)
  );
}

 

자 이제 게임 플레이를 해볼까요?

 

와 이제 진짜 테트리스 게임같네요!

 

어디 내놓아도 이건 이제 테트리스 게임이 맞다고 인정받을 순 있겠습니다.

 

기본적인 내용은 다 들어갔으니까요!

 

하지만 우리가 남겨놓은 백로그들이 있죠?

 

그것들을 다 구현할때 까진 끝난게 아닙니다!

 

이전에 남겨놓은 과제인 벽에 붙어있을때 회전시 밀어내기를 해봅시다.

 

rotateBlock(
  controlBlock,
  controlBlockArray,
  stackedBlockArray,
  allowableRange
) {
  let rotatedBlockArray = getLotatedBlock(
    this.blockType.rotationBlueprint,
    this.currentRotateDirection,
    controlBlockArray
  );

  if (rotatedBlockArray == null) {
    if (allowableRange > 0) {
      let couldLeftRotate = this.checkLeftMoveRotation(
        controlBlock,
        controlBlockArray,
        stackedBlockArray,
        allowableRange
      );

      if (couldLeftRotate) {
        return true;
      } else {
        return this.checkRightMoveRotation(
          controlBlock,
          controlBlockArray,
          stackedBlockArray,
          allowableRange
        );
      }
    } else {
      return false;
    }
  }

  if (!isOverlaped(rotatedBlockArray, stackedBlockArray)) {
    this.currentRotateDirection = getNextRotateDirection(
      this.currentRotateDirection,
      this.blockType.rotationBlueprint.length
    );
    controlBlock.blockArray = rotatedBlockArray;
    return true;
  } else {
    return false;
  }
}

checkLeftMoveRotation(
  controlBlock,
  controlBlockArray,
  stackedBlockArray,
  allowableRange
) {
  let tmpArray = copyBlockArray(controlBlockArray);
  if (couldBlockMoveToLeft(tmpArray, stackedBlockArray)) {
    moveToLeftOneLine(tmpArray);

    return this.rotateBlock(
      controlBlock,
      tmpArray,
      stackedBlockArray,
      allowableRange - 1
    );
  }
}
  
...
...

왼쪽벽과 오른쪽 벽을 체크하여, 오른쪽으로 밀어냈을때 회전할 수 있는지, 그리고 왼쪽으로 밀어냈을때 회전할 수 있는지를 체크하면 되겠죠?

 

4칸짜리 긴 블록은 두번 밀어져야 하기때문에, allowableRange를 2로 설정해 주었습니다.

 

이제 플레이를 해볼까요?

와우 이제 왼쪽 끝에서 회전을 해도 두칸 밀어져서 회전이 이루어 지도록 변경되었습니다!

 

앗.. 그런데 이미 쌓여있는 블럭의 옆에서 회전을 할시 밀어내는 로직이 빠졌네요..

 

가슴이 먹먹해져 오지만.. 이건 일단 다시 백로그에 넣어둡시다..

 

5부에 계속..

반응형
Comments