테트리스 웹 게임 만들기 (5) 블록 체크
1. 기존의 호출했던 renderBlock을 checkNextBlock으로 바꿈
기존의 바로 renderBlock을 해주던 것을 checkNextBlock을 거쳐서 renderBlock을 해주기 위해
전부 checkNextBlock으로 바꿔준다.
전체 코드는 아래와 같이 바뀌게 된다.
// js/tetris.js
'use strict'
import Blocks from './blocks.js'
export default class Tetris {
constructor() {
//setting
this.N = 20
this.M = 10
this.downInterval = undefined
//block
this.blockInfo = undefined
//dom
this.stage = document.querySelector('.stage')
//events
document.addEventListener('keydown', (e) => {
switch (e.keyCode) {
case 39:
this.moveBlock('m', 1)
break
case 37:
this.moveBlock('m', -1)
break
case 40:
this.moveBlock('n', 1)
break
case 38:
this.changeDirection()
break
case 32:
this.dropBlock()
break
default:
break
}
})
}
init() {
this.makeGround()
this.nextBlocks = []
for (let i = 0; i < 4; i++) {
this.makeNextBlock()
}
this.renderNextBlock()
this.makeNewBlock()
}
makeGround() {
this.ground = []
for (let i = 0; i < this.N; i++) {
this.ground.push('<tr>')
for (let j = 0; j < this.M; j++) {
this.ground.push('<td></td>')
}
this.ground.push('</tr>')
}
this.stage.innerHTML = this.ground.join('')
}
makeNextBlock() {
const blockArray = Object.entries(Blocks)
const randomIndex = Math.floor(Math.random() * blockArray.length)
this.nextBlocks.push(blockArray[randomIndex][0])
}
renderNextBlock() {
const next = document.querySelector('.next')
let temp = []
for (let i = 0; i < 4; i++) {
temp.push(
`<img class='tetris' src="./img/${this.nextBlocks[i]}.png" alt=${this.nextBlocks[i]}"/>`
)
}
next.innerHTML = temp.join('')
}
makeNewBlock() {
const next = this.nextBlocks.shift()
this.blockInfo = {
type: next,
direction: 0,
n: 0,
m: 3,
}
this.movingBlock = { ...this.blockInfo }
this.makeNextBlock()
this.renderNextBlock()
this.renderBlock()
this.checkNextBlock('start')
}
checkNextBlock(where = ''){
}
renderBlock() {
const { type, direction, n, m } = this.movingBlock
const temp = document.querySelectorAll('.moving')
temp.forEach((x) => {
x.classList.remove(type, 'moving')
})
Blocks[type][direction].forEach((block) => {
const x = block[0] + n
const y = block[1] + m
const target = this.stage.childNodes[x].childNodes[y]
target.classList.add(type, 'moving')
})
this.blockInfo.n = n
this.blockInfo.m = m
this.blockInfo.direction = direction
}
moveBlock(where, amount) {
this.movingBlock[where] += amount
this.checkNextBlock(where)
}
changeDirection() {
const direction = this.movingBlock.direction
direction === 3
? (this.movingBlock.direction = 0)
: (this.movingBlock.direction += 1)
this.checkNextBlock(direction)
}
dropBlock() {
clearInterval(this.downInterval)
this.downInterval = setInterval(() => {
this.moveBlock('n', 1)
}, 8)
}
}
2. 블록체크
테트리스 게임을 만들면서 가장 많이 수정했던 부분이다 그래서인지 코드가 여기저기 꼬였다.
1. 방향 전환으로 블록체크를 할 경우 moveAndTurn()을 실행해줄 예정
- 블록이 바닥에 도착하지 않았으나 방향 전환했을 시, 옆에 블록이 이미 있다면 그 자리에서 freeze 되는 것을 방지
2. 그 외 이동이 범위 밖이라면 이전의 블록을 현재 블록에 업데이트
- 세로의 값이 범위 밖이라면 가장 아래라는 뜻이므로 finishBlock()으로 블록을 프리징 해줄 예정
3. 그 외 이동이 범위 안이라면 아래로 이동인지 좌우로 이동인지 두 가지를 체크
- 아래로 이동일 경우 : 다음 이동위치에 이미 블록이 있다면 이전의 블록을 현재 블록에 업데이트
- 그 외 이동일 경우 : 다음 이동위치에 이미 블록이 있다면 이전의 블록을 현재 블록에 업데이트
만약 where가 'start'일 경우 : 블록이 생성될 위치에 블록이 있으니 게임 종료
4. 그 외 :나머지 블록의 구성요소를 모두 체크
5. 4가지의 블록 요소들을 체크해서 모두 유효하다면 renderBlock()
checkNextBlock(where = ''){
const { type, direction, n, m } = this.movingBlock
let isFinished = false
Blocks[type][direction].some((block) => {
const x = block[0] + n
const y = block[1] + m
// changeDirection일 경우
if (where === 0 || where === 1 || where === 2 || where === 3) {
// moveAndTurn()
// change Direction의 유효성 체크
}
// 그외 이동일 경우 : 좌우 밖이라면 기존의 bolockInfo으로 render
else if (y < 0 || y >= this.M) {
this.movingBlock = { ...this.blockInfo }
this.renderBlock()
return true
}
// 그외 이동일 경우 : 아래 범위 밖이라면 blockInfo상태를 finishBlock(블록 얼리기)
else if (x >= this.N) {
this.movingBlock = { ...this.blockInfo }
isFinished = true
this.finishBlock()
return true
}
// 그외 이동일 경우 : 범위 안이라면
else {
const target = this.stage.childNodes[x]
? this.stage.childNodes[x].childNodes[y]
: null
// 아래로 이동일 경우
if (where === 'm') {
// 다음 블록이 가야할 자리가 finish클래스(먼저 정착한 블록이 있다면)을 가지고 있다면
// 기존의 blockInfo로 movingBlock 업데이트
if (target && target.classList.contains('finish')) {
this.movingBlock = { ...this.blockInfo }
}
}
// 그외 : 좌,우 이동 & 처음 시작했을 경우
else {
// 범위 내이지만 해당 위치에 블록이 이미 있을 경우
if (target && target.classList.contains('finish')) {
isFinished = true
this.movingBlock = { ...this.blockInfo }
// 만약 처음 렌더링 된 블록이라면 게임 종료
if (where === 'start') {
setTimeout(() => {
//finishGame()
console.log('게임종료')
}, 0)
return true
}
// 그외 : 블록 얼리기 (finishBlock)
else {
this.finishBlock()
return true
}
}
}
}
})
// 블록을 구성하는 4가지 요소가 모두 유효하다면
if ((where === 'n' || where === 'm') && !isFinished) {
this.renderBlock()
}
}
3. 블록 얼리기
이제 블록이 바닥에 도달하거나 다른 블록 위에 올려졌을 때 블록을 얼려보자
경우의 수는 위 checkNextBlock에서 체크를 해줬으니 finishBlock을 정의해주면 된다.
downInterval를 clear 해주고 moving이라는 클래스를 없애주고 전부 finish라는 클래스를 넣어준다.
이후 makeNewBlock으로 새로운 블록 생성
finishBlock() {
clearInterval(this.downInterval)
const temp = document.querySelectorAll('.moving')
temp.forEach((block) => {
block.classList.remove('moving')
block.classList.add('finish')
})
// 이후 부실수 있는 블록 체크후 부시기
this.makeNewBlock()
}
다음에는 방향 전환을 완성하고 자동으로 블록 이동과 속도 및 lv설정 블록 부수기를 구현해보자
'Project > 테트리스 (javascript)' 카테고리의 다른 글
[JavaScript] 테트리스 웹 게임 만들기 (7) 기능 마무리 (0) | 2022.03.03 |
---|---|
[JavaScript] 테트리스 웹 게임 만들기 (6) 블록 부수기 (0) | 2022.02.20 |
[JavaScript] 테트리스 웹 게임 만들기 (4) 블록 이동 및 전환 (0) | 2022.02.15 |
[JavaScript] 테트리스 웹 게임 만들기 (3) 블록 정의 및 렌더링 (0) | 2022.02.11 |
[JavaScript] 테트리스 웹 게임 만들기 (2) 테트리스 게임 판 (0) | 2022.02.09 |