WORDLE 게임 만들기
- 보드판은 총 5x5 사이즈
- 한 타일에 알파벳 하나씩 입력할 수 있고 한 줄은 한 번의 시도이다
- 단어를 입력하고 엔터를 누르면 타일의 색이 바뀌면서 정답에 대한 힌트를 알려주고 다음 줄로 이동
html 구조
1 | <!-- index.html --> |
game-board들은 한 줄이 되고
그 안의 board__text는 각 줄의 한 칸이 된다
CSS
1 | /* style.css */ |
Javascript
초기값
1 | let word = 'APPLE' // 정답 단어 |
각 타일에 접근하기
1 | let rowArr = document.querySelectorAll('.game-board') |
각 줄을 querySelectorAll로 가져온다
console.log(rowArr)로 확인 해 보면
nodeList가 가져와 진다
배열의 형태로 보이지만 배열이 아닌 유사배열이다.
그러므로 배열에서 제공하는 메서드가 안먹히는 경우가 있다
mdn문서를 찾아보니
nodelist는 array는 아니지만 forEach()를 사용하여 반복할 수 있고,
Array.from()을 사용하여 Array로 변환 할 수도 있다.
주의점은 오래된 브라우저에서는 forEach()나 Array.from()을 지원 하지 않는다
https://developer.mozilla.org/ko/docs/Web/API/NodeList
콘솔에서 요소를 클릭해보면 사용가능한 속성들이 나오는데 그중에서 자식노드에 접근할 수 있는
children 속성이다
rowArr[index번호].children[index번호] 로 각 타일에 접근이 가능해졌다!!
이 부분에 많이 막혔었다.. 줄 따로 칸 따로 받아와서 조작할려다 보니
계속 뭔가가 꼬여서 안됐었는데 줄의 요소만 받아와서 그 줄의 자식요소들에 접근하니 쉬워졌다
keyboard event
키보드를 눌렀을때 각 칸에다가 누른 키보드의 글자를 넣는다
1 | document.addEventListener('keyup', event => { |
키를 눌렀다 떼면 이벤트가 발생하고 그 이벤트를 콘솔로 찍었을때 사용가능한 속성들이 나온다
그 중 keyCode를 쓸려고 적었더니 밑줄이 쫙..
mdn 문서를 찾아보니 빨간색 휴지통 모양과 함께
더 이상 사용되지 않음: 이 기능은 더 이상 권장되지 않습니다. 일부 브라우저는 여전히 이를 지원할 수 있지만 관련 웹 표준에서 이미 제거되었거나 삭제 과정에 있거나 호환성 목적으로만 유지될 수 있습니다. 사용을 피하고 가능하면 기존 코드를 업데이트하십시오. 이 페이지 하단의 호환성 표를 참조하여 결정을 내리십시오. 이 기능은 언제든지 작동을 중지할 수 있습니다.
이라는 설명이 keyCode 외에도 중지되는 속성들이 몇 개 더 있었다
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
- 그럼 난 무엇으로 키보드 범위를 지정할 수 있는가?
A-Z까지의 범위만 입력받기 위해 keyCode를 사용할려고 했는데 권장하지 않는다니 다른걸 써야 했다
1 | document.addEventListener('keyup', event => { |
keyCode가 숫자로 출력되어 더 그럴싸 하게 보일뿐 키값의 순서는 똑같았다
그냥 key 속성으로도 범위를 지정 할 수 있었다.
1 | document.addEventListener('keyup', event => { |
이제 각 키보드를 눌렀을때 동작하는 부분에
그에 알맞는 로직을 짜주면 된다..
타일에 글자 넣기
- 현재 줄(row)의 index를 알아낸다
- 현재 줄(row)의 타일(tile)의 index를 알아낸다
- 그 타일(tile)에 키보드로 누른 키값(event.key)을 텍스트로 넣는다
- 타일(tile)의 index는 정답단어의 길이를 넘지 않는다!
현재 초기값으로
boardRow = 0
tileNum = 0
word = ‘APPLE’ 인 상태
좌측 위인 0, 0에서 시작한다
만약 키를 눌러 텍스트가 입력되면 다음 칸인 0, 1로 이동한다
1 | document.addEventListener('keyup', event => { |
타일에 글자 지우기
1 | document.addEventListener('keyup', event => { |
tileNum -= 1; 과
let currTile = rowArr[boardRow].children[tileNum] 의 순서가 중요
타일에 5글자를 꽉 채웠을 경우 tileNum은 5가 된다
근데 nodeList로 받아온 children[tileNum]의 tileNum 부부은 인덱스 번호이기 때문에 5번째 칸의 인덱스 번호가 4이다!
그렇기 때문에 -1 을 먼저 해주고 현재 타일의 텍스트를 비워주는게 중요하다
다음 줄(row)로 넘어가기
엔터를 누르면 boardRow가 +1 이 되고 tileNum = 0이 되어야 한다
좌표가 1,0 에서 시작 한다
1 | document.addEventListener('keyup', event => { |
정답여부 체크
- 각 타일에 적힌 글자를 조회해 정답 글자와 비교한다
- 타일에 적힌 글자가 정답에 포함되어 있으며, 순서까지 같으면 초록색
- 타일에 적힌 글자가 정답에 포함만 되어있으면 노란색
- 아무것도 일치 하지 않으면 회색
- 각 색상은 클래스 추가로 변경 해준다
- 클래스는 .board__text와 일치선택자로 작성하는게 중요 (띄어쓰기하면 자식 선택자가 된다)
1
2
3
4
5
6
7
8
9.container .board--wrap .game-board .board__text.good{
background-color: #22c566;
}
.container .board--wrap .game-board .board__text.littlegood{
background-color: #c0c522;
}
.container .board--wrap .game-board .board__text.bad{
background-color: #ccc;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34함수 생성
function gameCheck(){
let wordCheck = 0;
// 초록색 글자를 체크할 변수 wordCheck가 5가 되면 한 줄이 다 정답인셈
for(let i = 0; i < word.length; i++){
//정답단어의 길이만큼 반복한다 0부터 시작이니 0~4 총 5번 반복
let currTile = rowArr[boardRow].children[i]
// 현재 타일을 조회한다
// 엔터를 한 번 쳤다면 현재 타일은 rowArr[0].children[0~4] 번째
// 즉, n번째 줄의 i만큼 반복하는 0~4번째 인덱스의 타일을 조회 한다.
let answer = currTile.textContent;
// answer는 조회하는 타일 안의 text
if(answer === word[i]){
// answer가 맞는 자리에 있으면
// 그리고 정답갯수 +1
currTile.classList.add('good');
wordCheck += 1;
}
else if(word.includes(answer)){
// 정답단어 안에 answer가 포함되어 있는 경우
currTile.classList.add('littelgood')
}
else {
// 그리고 아무것도 해당 되지 않는 경우
currTile.classList.add('bad')
}
// 게임 성공 여부
if(wordCheck === word.length){
// 정답 갯수와 정답단어의 길이가 같으면 gameOver가 true!
gameOver = true;
}
}
}
모달창 띄우기
- 정답 여부를 체크해서 정답/실패 모달창을 띄워준다
- gameCheck()함수 안의 게임 성공 여부에 추가 작성한다
1 | <!-- index.html --> |
index.html에 popup 자리 생성
1 | /* style.css */ |
현재 모달창은 display:none 상태이다
이후에 정답/실패를 해서 창이 생기게 하기 위해 일치 선택자로 .display–flex를 추가 작성한다
- 몇 번째 줄이든 성공시 정답 모달창이 뜬다
- 실패시에는 마지막 줄까지 가서 실패 모달창이 떠야 한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47function gameCheck(){
// ...
// 게임 성공 여부
if(wordCheck === word.length){
gameOver = true; // 성공시 종료
// modal 생성
let modal = document.querySelector('.popup')
modal.innerHTML = `
정답
<button class="popup--btn">Reset</button>
`
model.classList.add('.display--flex')
// .display--flex 클래스가 붙으면서 display:none 이 flex로 바뀌며 나타난다
// btn reload
const resetBtn = document.querySelector('.popup--btn')
resetBtn.addEventListener('click',()=>{
window.location.reload()
// 버튼을 눌렀을 경우 창을 다시 새로고침 해주자......
})
}
// 실패 여부
else if(wordCheck < word.legnth && rowArr[boardRow].dataset.row === '4'){
// 정답갯수가 단어의 길이보다 작을경우
// wordCheck < word.legnth만 넣을 경우 첫 줄에서 실패 할시 바로 실패 모달창이 떠버린다..
// 마지막줄까지 가서 체크하는 조건문을 추가해줘야 한다
// 다른 방법도 있겠지만.. 잘 모르겠어서 dataset을 이용했다
// 마지막줄의 dataset.row는 4(문자열)이므로 마지막줄까지 작성해야 조건문이 만족된다
gameOver = true; // 게임종료
// modal 생성
let modal = document.querySelector('.popup')
modal.innerHTML = `
실패
<button class="popup--btn">reset</button>
`
modal.classList.add('display-flex')
// btn reload
const resetBtn = document.querySelector('.popup--btn')
resetBtn.addEventListener('click',()=>{
window.location.reload()
})
}
}
dataset
1 | <div data-row="0" class="game-board"> </div> |
각 줄(row)에는 data-row가 0부터4까지 들어가있다
콘솔로 조회해 보면 0~4 문자열이 출력된다.
1 | console.log(rowArr[boardRow].dataset.row) |
button 추가는 part.2