기술 관련/etc

지뢰찾기를 만들어보자 #7 - 게임 스코어 구현

ID 홍차 2022. 10. 5. 20:21

지난번 지뢰찾기의 난이도 조절을 대해 다루어 보았었다. https://mc500.tistory.com/673  이번 글에서는 좀 더 게임답게 게임 점수에 대한 부분을 만들어 보도록 하자.

 

지뢰찾기의 승리조건은 지뢰가 없는 안전한 곳을 다 찾는 것이다. 그리고 한 번이라도 지뢰를 건드리면 실패다. 따라서, 게임 점수로서 정할만한 것이 게임을 시작해서 승리까지 걸린 시간이 가장 적절한 것으로 보이므로, 가장 빠른 시간에 승리를 한 것을 최고 점수로 기록할 수 있도록 한다.

 

게임 기록은 어딘가에 저장을 해 놓을 수 있는 방법이 있지만 나중에 개선 사항으로 남겨 두기로하고, 이번 글에서는 단지 기능만 구현하기로 한다.

 

우선 게임 점수와 시작 시간에 대한 변수를 먼저 구성한다.

  highscores: {
    beginner: 999,
    intermediate: 999,
    expert: 999,
  },
  start_time: 0,
  elapsed_time: 0,

 

물론 elapsed_time은 initGame() method 에서 0으로 초기화 해주어야 한다. 그리고 나서 점수를 표시할 HTML을 추가한다.

<div>
  <span>{{elapsed_time}} sec(s)</span>
</div>
<br>

대략 다음과 같은 모습이 된다.

 

게임을 시작하면 타이머를 실행해서 그 때 부터 일정 시간이 지났을 때 정보를 갱신해 주도록 해야하고, 게임이 끝났을 때는 타이머를 중지하고 현재 시간을 기준으로 최종 점수를 입력하게 한다.

 

우선은 게임 종료 시점에 gameover=true로 처리하는 것을 finishGame()이라는 method를 만들고 호출하도록 코드를 변경한다. 그리고, 이 때 성공 실패 정보도 같이 받도록 한다.

finishGame(win) {
  this.gameover = true
  if (win) {
	this.alert('You Win!')
  } else {
	this.alert('Bomb!')
  }
},

 

게임을 시작하는 시간은 New Game 버튼을 클릭했을 때가 아닌 상자를 제일 먼저 클릭 했을 때가 되어야 한다. 이를 위해 첫 번째 클릭 여부를 판단하는 변수가 있어야 한다. 그런데 새로이 추가 하기보다는 게임 시작 시간인 start_time 변수 값이 0인 경우 아직 게임이 시작되지 않은 것으로 여길 수 있으므로 이를 이용하도록 한다.

 

this.canvas.addEventListener("mousedown", function(evt) {
  let x = Number.parseInt(evt.offsetX/self.box_width)
  let y = Number.parseInt(evt.offsetY/self.box_width)
  evt.preventDefault()
  evt.stopPropagation()

  if (self.gameover) {
    return false
  }
  
  if (self.start_time == 0) {
    self.start_time = new Date().getTime()
    self.scoreIntervalId = setInterval(() => {
      let diff = (new Date().getTime()) - self.start_time
      self.elapsed_time = Math.round(diff/1000)
    }, 1000)
  }

이제 finishGame() 에서 타이머를 중지하고 최종 점수를 저장한다.

finishGame(win) {
  let record = this.elapsed_time
  if (this.scoreIntervalId) {
    clearInterval(this.scoreIntervalId)
    this.scoreIntervalId = undefined
  }
  this.gameover = true

  if (win) {
    this.alert('You Win!')
    this.highscores[this.level] = record
  } else {
    this.alert('Bomb!')
  }
},

또한, 게임을 포기하고 새로 게임을 시작하는 경우가 있으므로 initGames()에도 타이머를 중지 코드를 작성한다.

initGames() {
  this.gameover = false
  this.cleared = 0
  this.start_time = 0
  this.elapsed_time = 0
  this.flags = 0

  if (this.scoreIntervalId) {
    clearInterval(this.scoreIntervalId)
    this.scoreIntervalId = undefined
  }

추가로 현재 지뢰의 갯수와 깃발의 수를 비교하여 남은 지뢰의 수를 알 수 있도록 HTML에 정보를 추가해준다.

<div>
  <span>{{elapsed_time}} sec(s), {{mines - flags}} left</span>
</div>

 

다음 글에서는 Windows 지뢰찾기에서와 같이 노란 스마일 얼굴 버튼으로 게임 시작/종료를 구성 하는 내용을 다루어 보도록하겠다.