-
지뢰찾기를 만들어보자 #3 - 게임 로직 구성기술 관련/etc 2022. 9. 24. 10:32
지난번 어느정도 필요한 부분을 확인해 보았다. 이제는 이를 이용해서 좀 더 상세 구성을 해 보기로 하자.
https://mc500.tistory.com/669
우선은 랜덤으로 지뢰를 생성하고 어떻게 나오는지 확인해 보자. 먼저 각 상자에 대한 정보를 초기화 한다.// Init box let boxes = [] let n = this.mines for (let y=0;y<this.height;y++) { for (let x=0;x<this.width;x++) { let box = { row: x, column: y, value: 0, flagged: false, revealed: false, } if (n != 0 && Math.floor(Math.random() * this.mines) == 0) { box.value = 'M' // Mine n-- } boxes.push(box) } }
그리고, 앞서 만들었던 drawBox 함수를 변경하여 box의 정보를 표기하도록 하면 다음과 같이 출력되는 것을 볼 수 있다.이제 상자 정보를 초기화 할 때 각 위치에서 주변에 Mine이 몇 개나 있는지를 생성해 주면 된다. 현재 상자를 기준으로 8곳(상, 하, 좌, 우, 좌상, 우상, 좌하, 우하)을 확인하며 주변에 지뢰가 있는 경우를 판단하여 자신이 가진 값을 증가시킨다.
evaluateMineHint(x, y) { let value = Number(this.boxes[x+y*this.width].value) if (!Number.isNaN(value)) { this.boxes[x+y*this.width].value = value + 1 } },
힌트 숫자가 완성되었다면 이제 M 표시 대신 폭탄 그림을 나오도록 코드를 변경해 보자그 다음으로는 마우스로 상자를 클릭했을 때 해당 영역의 정보가 어떤 것인지를 확인하는 부분이다. 마우스 우 클릭을 한 경우 해당 박스의 정보에 따라 깃발, 힌트 또는 폭탄 정보를 확인한다.
this.canvas.addEventListener("mouseup", function(evt) { let x = Number.parseInt(evt.offsetX/self.box_width) let y = Number.parseInt(evt.offsetY/self.box_width) evt.preventDefault() evt.stopPropagation() console.log('mouse up: '+evt.button+': '+x+','+y) let box = self.boxes[x+y*self.width] if (!box) { console.error('box is undefined: '+x+','+y) return false } if (evt.button == 0) { if (box.flagged) { alert('Flagged') } else if (box.value == CONST_MINE) { alert('Bomb!') } else { alert(box.value) } } else if (evt.button == 2) { if (box.flagged) { box.flagged = false alert('Unflagged') } else { box.flagged = true alert('Flagged') } } return false }, false)
마우스 좌/우 버튼을 동시에 클릭을 인식해서 처리할 수도 있지만 나중에 기능 개선 항목으로 남겨 둔다.
마우스 동작 인식이 되었다면 이제 우클릭을 하여 정보를 확인한 경우와 좌클릭일 때 깃발 정보를 표기하는 부분을 구현한다.if (box.flagged) { box.flagged = false self.drawBox(box) } else { box.flagged = true self.drawBox(box) }
여기에 현재 깃발이 몇 개 생성되었는지 정보를 보여주는 정보를 등록하면 다음과 같이된다.
if (box.flagged) { box.flagged = false self.flags-- if (self.flags < 0) { self.flags = 0 } self.drawBox(box) } else { box.flagged = true self.flags++ self.drawBox(box) }
이제 0인 경우 자동으로 확장해주는 부분을 구현하면 기본적인 게임으로서의 모양은 완성된다고 본다. 앞서 지뢰 주변의 숫자 힌트를 구성할 때도 8곳을 확인 했던것 처럼 이 경우도 특정 박스의 주변에 대한 해당 정보를 확인하고 값이 0인 경우 이를 열어야 한다. 이를 위해 다음과 같은 공통 함수를 만들어 사용해 볼 수 있다.
traverseBoxes(x, y, callback) { let limitW = this.width - 1 let limitH = this.height - 1 if (x > 0) { // Left callback(x-1, y) // Left-Top if (y > 0) { callback(x-1, y-1) } // Left-Bottom if (y < limitH) { callback(x-1, y+1) } } if (x < limitW) { // Right callback(x+1, y) // Right-Top if (y > 0) { callback(x+1, y-1) } // Right-Bottom if (y < limitH) { callback(x+1, y+1) } } // Top if (y > 0) { callback(x, y-1) } // Bottom if (y < limitH) { callback(x, y+1) } }
자동으로 열어주는 것은 사용자가 클릭을 했을 때 0인 경우 부터 시작하며 각각의 박스를 탐색하여 0인 경우 이를 다시 호출하는 재귀 구조를 가지게 된다.
expandSafeArea(x, y) { let box = this.boxes[x+y*this.width] if (box.value == 0 && !box.revealed) { box.revealed = true this.drawBox(box) this.traverseBoxes(x, y, this.expandSafeArea) } },
근데 보통은 0 주변까지는 확인해주므로 이를 구현하면 다음과 같다.
expandSafeArea(x, y) { let box = this.boxes[x+y*this.width] if (!box.revealed) { box.revealed = true this.drawBox(box) if (box.value == 0) { this.traverseBoxes(x, y, this.expandSafeArea) } } },
이제 0인 경우는 굳이 표현할 필요가 없으므로 그리지 않도록 코드를 수정하면 다음과 같이 나타난다.
어느정도 완성이 된 상태지만 아직 게임이 완성되려면 몇 가지 손봐야 할 부분이 남았다. 현재 구현은 깃발을 아무곳에나 둘 수 있는데, 이미 박스가 열려서 확인이 된 곳도 둘 수 있고, 심지어 숫자 위에도 둘 수 있다.
따라서, 깃발을 놓거나 빼기 전에 이미 박스가 열려있는지 여부를 확인하도록 해야 한다.
} else if (evt.button == 2) { if (box.revealed) { return false } if (box.flagged) {
그리고 깃발 관련하여 또 하나 수정해야 하는 부분이 있는데, 상자가 아무 것도 열리지 않은 상태에서 깃발을 두고 자동으로 확장되어 열렸을 때 해당 깃발이 놓여져 있는 부분이 빈곳이라면 같이 열리도록 되어 있다.
따라서, 만약 상자에 깃발이 있다면 더 이상 확장되지 않도록 조치가 되어야 한다.
expandSafeArea(x, y) { let box = this.boxes[x+y*this.width] if (!box.revealed && !box.flagged) { box.revealed = true
깃발이 정상적으로 동작하면 다음과 같이 깃발이 있는 곳은 자동으로 열지 않는다.
지뢰찾기에 대한 어느정도 기능이 완성되었다. 남은건 게임의 승리 조건을 구현하는 것인데 이것은 다음 글에서 다루도록 하겠다.
'기술 관련 > etc' 카테고리의 다른 글
지뢰찾기를 만들어보자 #5 - 사용성 개선 (0) 2022.09.28 지뢰찾기를 만들어보자 #4 - 승리 조건 구성 (1) 2022.09.25 지뢰찾기를 만들어보자 #2 - 기본 환경 구성 (0) 2022.09.17 지뢰찾기를 만들어보자 #1 - 지뢰 찾기 게임 배경 (0) 2022.09.14 정규식 Lookahead와 Lookbehaind (0) 2022.05.16