지뢰찾기를 만들어보자 #2 - 기본 환경 구성
지난번에 지뢰찾기를 만들어보겠다고 하고 말았는데 이번 글부터는 필요한 부분을 하나씩 확인해 보자.
https://mc500.tistory.com/668
Breakout 예제에서와 같이 Pure Javascript 를 이용할 수도 있겠지만, 웹 SPA이면서도 비교적 간단히 사용할 수 있는 Vue.js를 기반 framework으로 시작해 보기로 했다. 여기서 Vue.js에 대한 설명을 할 것은 아니고 상세 내용은 https://vuejs.org/ 를 참고하기 바란다.
Vue CLI의 create 명령을 이용하면 Vue.js로 구성된 간단한 프로젝트가 만들어진다. 그리고 yarn이나 npm 명령으로 필요한 모듈을 설치하고 서버를 실행 할 수 있는데, 웹 브라저로 http://localhost:8080/ 에 접속하면 아래와 같은 웹페이지를 볼 수 있게된다.
저 화면을 표기하는 HelloWorld.vue의 내용을 이렇게 바꾸면 기본 세팅은 끝
<template>
<div>
<h1>Mine Sweeper</h1>
<canvas id="base" width="480" height="320"></canvas>
</div>
</template>
<script>
export default {
name: 'MineSweeper',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
canvas {
background: red;
display: block;
margin: 0 auto;
}
</style>
배경이 흰색이라 Canvas 영역은 눈에 일부러 눈에 띄게 빨간색으로 지정했다.
이제 지뢰 게임에 필요한 정보를 생각해보면 다음과 같다.
1. 가로x세로 격자 정보
2. 지뢰의 갯수
Vue Compoment로 형태이므로 아래 같이 property를 정의하고 이 값을 초기화해서 사용하는 방식으로 구성해 볼 수 있다.
props: {
width: Number,
height: Number,
mines: Number
}
그러면, App.vue에서는 다음과 같이 값을 정의해서 호출할 수 있다.
<template>
<HelloWorld :width="10" :height="10" :mines="5"/>
</template>
조건이 갖춰졌으니 이제 이 요소를 배치를 해봐야 한다. 일반적으로 Mine 영역에대한 단위 크기를 고정하고 격자의 크기를 구상하게 된다. 먼저 우선은 단위 크기를 30x30에 둘레에 1px 정도의 테두리를 둔다고 가정하고 10x10의 영역을 채우면 다음과 같다.
위의 상자를 그리는 모듈에 대한 함수는 다음과 같이 drawBox라는 methods를 만들어 볼 수 있다.
drawBox(x, y) {
let ctx = this.ctx
let sq = this.box_width
// Fill
ctx.beginPath()
ctx.rect(x*sq, y*sq, sq, sq)
ctx.fillStyle = "#00ff00"
ctx.fill()
ctx.closePath()
// Outlined
ctx.beginPath()
ctx.rect(x*sq, y*sq, sq, sq)
ctx.strokeStyle = "rgba(0, 0, 255, 0.5)"
ctx.stroke()
ctx.closePath()
}
상자가 만들어졌다면 이제 지뢰 또는 숫자와 같은 정보를 배치할 수 있는지를 확인해 본다.
숫자가 나왔으니 이제는 Marker, Mine 을 어떻게 표기할지에 대해 고민해 봐야 한다. 이런 경우 깃발과 폭탄을 그리는 방법도 있지만 그림으로 그려진 이미지 파일을 이용하는 방법이 있다. 이번에는 이미지 파일을 이용하기로 했다.
이 깃발과 폭탄 이미지는 하나의 이미지이다. HTML Canvas의 drawImage를 이용하면 필요한 위치에 원본 이미지 내의 구역을 나눈 후 크기를 조절하여 폭탄이나 깃발을 선택적으로 보여줄 수 있다.
// draw flag
ctx.drawImage(this.sprite, 0, 0, 1162, 1162, x, y, w, w)
// draw mine
ctx.drawImage(this.sprite, 1162, 0, 1162, 1162, x, y, w, w)
이제 마우스로 어떤 박스를 선택했는지 확인해 보는 남았는데 Canvas를 클릭시 전달 되는 마우스의 좌표를 역산하여 해당 위치의 박스 위치를 알아 낼 수 있었다.
this.canvas.addEventListener("click", 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('click: '+x+','+y)
return false
}, false);
this.canvas.addEventListener("contextmenu", 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('context: '+x+','+y)
return false
}, false);
기본적으로 필요한 부분은 다 모은것 같다. 이제 이를 조합해서 게임을 만들어 볼 차례다.