짝맞추기 게임이란?

플레이어는 원하는 카드 두장을 뒤집습니다. 2장이 같은 숫자일 경우 점수를 획득할수 있으며, 한번더 플레이 하는게 가능합니다. 만약, 두장이 서로 다른 카드인 경우 카드를 원래대로 돌려놓고 다른 플레이어가 플레이 하도록 한다. 모든 카드를 뒤집었을때 획득한 점수가 많은쪽이 승리하게 된다.

인용ーWikipidia

시작하기 전에

만약 소스를 참고로 하여 게임을 만들고 싶으신 분은 처음하는 Web기본을 처음부터 한번 훑어보는것을 추천드립니다.

조작방법

MAC、WINDOW : 마우스로 화면을 클릭해서 카드를 뒤집을수 있습니다.
Mobile : 화면을 터치하여 카드를 뒤집을수 있습니다.

실행 결과

(환경에따라 디자인이 다를수도 있습니다.)

다운로드

소스코드

<!DOCTYPE html>
<html>
<head>
	<title>Flip Cards</title>
	<meta charset="utf-8">
	<style>
		td.card {
			width: 100px;
			height: 140px;
			border: 1px solid blue;
			border-radius: 10px;
			text-align: center;
			font-size: 36px;
			box-shadow: rgb(128, 128, 128) 5px 5px;
		}
		td.back {
			background-image: url("card.png");
			background-size: 100px 140px;
		}
	</style>
	<script>
		"use strict";
		//배열 셔플
		Array.prototype.shuffle = function() {

			var i = this.length;
			while (i) {
				var j = Math.floor(Math.random()*i);
				var t = this[--i];
				this[i] = this[j];
				this[j] = t;
			}
			return this;
		}

		// 광역변수
		var timer = NaN, score = 0, flipTimer, prevCard, startTime;

		// 초기화 함수
		function init() {
			var table = document.getElementById("table");
			var cards = [];
			for(var i=1; i <= 10; i++) {
				cards.push(i);
				cards.push(i);
			}
			cards.shuffle();

			for(var i=0; i<4; i++) {
				var tr = document.createElement("tr");

				for(var j=0; j<5; j++) {
					var td = document.createElement("td");
					td.className = "card back";
					td.number = cards[i*5 + j];
					td.onclick = flip;
					tr.appendChild(td);
				}
				table.appendChild(tr);
			}

			startTime = new Date();
			timer = setInterval(tick, 1000);
		}

		//경과시간 측정 타이머
		function tick() {
			var now = new Date();
			var elapsed = Math.floor((now.getTime() - startTime.getTime())/1000);
			document.getElementById("time").textContent = elapsed;
		}

		//카드 뒤집기
		function flip(e) {
			var src = e.srcElement;
			if(flipTimer || src.textContent != "") {
				return;
			} 

			var num = src.number;
			src.className = "card";
			src.textContent = num;

			switch (num) {
				case 1:
					src.style.backgroundImage = 'url("1.png")'
					break;
				case 2:
					src.style.backgroundImage = 'url("2.png")'
					break;
				case 3:
					src.style.backgroundImage = 'url("3.png")'
					break;
				case 4:
					src.style.backgroundImage = 'url("4.png")'
					break;
				case 5:
					src.style.backgroundImage = 'url("5.png")'
					break;
				case 6:
					src.style.backgroundImage = 'url("6.png")'
					break;
				case 7:
					src.style.backgroundImage = 'url("7.png")'
					break;
				case 8:
					src.style.backgroundImage = 'url("8.png")'
					break;
				case 9:
					src.style.backgroundImage = 'url("9.png")'
					break;
				case 10:
					src.style.backgroundImage = 'url("10.png")'
					break;
			}

			// 1장
			if(prevCard == null) {
				prevCard = src;
				return;
			}

			// 2장
			if(prevCard.number == num) {
				if(++score == 10) {
					clearInterval(timer);
				}
				prevCard = null;
				clearTimeout(flipTimer)
			} else {
				flipTimer = setTimeout(function() {
					src.className = "card back";
					src.textContent = "";
					prevCard.className = "card back"
					prevCard.textContent = "";
					prevCard.style.backgroundImage = 'url("card.png")'
					prevCard = null;
					flipTimer = NaN;
					src.style.backgroundImage = 'url("card.png")'
				}, 1000);
			}
		}
		
	</script>
</head>
<body onload="init()">
	<table id="table"></table>
	<h2>
		경과시간: <span id="time">0</span>
	</h2>
</body>
</html>

소스코드 해설

CSS부터 보도록 합시다.

  • 7열,16열 – <style>요소에서는 td.card(카드의 크기, 폰트 사이즈등)과 td.back(뒷면)이라는 두개의 셀렉터를 정의 합니다. JavaScript에서는 스타일을 동적으로 적용하기 위해서 이하와 같은 처리를 행합니다.
element.className = "card back";
element.className = "card";

여기서 “element”는 td요소를 참조하는 변수입니다. 프로그래밍 소스에서는 td라는 변수나 src라는 변수를 사용합니다.

class속성을 JavaScript에서 설정할때에는 className속성에 값을 대입합니다. 대입하는 ㅏㅄ을 공백으로 구분지음으로 인해, 여러개의 셀렉터를 한번에 설정할수 있습니다.

  • 17열 – 참고로「background-image: url(“card.png”);」는 배경 그림을 설정하는 CSS스타일 입니다.
  • 24열 – 배열의 요소를 램덤으로 섞는 함수 입니다.
  • 37열 – 사용된 광역 변수는 아래와 같습니다.
변수 설명
timer 1초마다 tick()을 호출하는 타이머 입니다.
fliptimer 2장째에 넘긴 카드를 한동안 표시 상태로 해주는 타이머 입니다.
score 몇페어를 맞췄는지 확인
prevCard 1장째에 넘긴 카드 정보
startTimer 처음 게임을 시작한 시간

이 에김에서는 두개의 타이머를 사용하고 있습니다.

timer는 경과 시간을 측정하기 위한 것으로setInterval, clearInterval에서 제어합니다. 한편 flipTimer는 1초뒤에 카드를 뒤집기 위한 것으로setTimeout、clearTimeout에서 제어 됩니다. 헷갈리지 않도록 주의 하도록 합시다.

  • 40열 – 초기화 함수 init()함수를 실행합니다.
  • 42열 ~ 47열 – 20장(페어 x 10조합)을 무작위로 배열합니다.
  • 49열 – 그후 2중 for문으로 카드를 나열합니다. 15puzzle와 똑같은 처리를 하고 있으므로 자세한 처리는 15puzzle를 참고해 주시기 바랍니다.
  • 67열 ~ 71열 – tick()함수에서는 경과 시간을 표시합니다.
    • 68列 – newDate()에서는 현재시간을 취득합니다.
    • 69列 – Date오브젝트의 getTime()함소에서 1970년1월1일00:00:00UTC로 부터 경과 밀리초를 취득 합니다. 게임 개시nit()함수를 실행합니다.
    • 42열 ~ 47열 – 20장(페어 x 10조합)을 무작위로 배열합니다.
    • 49열 – 그후 2중 for문으로 카드를 나열합니다. 15puzzle와 똑같은 처리를 하고 있으므로 자세한 처리는 15puzzle를 참고해 주시기 바랍니다.
    • 67열 ~ 71열 – tick()함수에서는 경과 시간을 표시합니다.
    • 68列 – newDate()에서는 현재시간을 취득합니다.
    • 69列 – Date오브젝트의 getTime()함소에서 1970년1월1일00:00:00UTC로 부터 경과 밀리초를 취득 합니다. 게임 개시할때의 시간을 취득하여, 1000으로 나눔으로 인해 초단위로 경과시간을 취득하여 화면에 표시합니다.
  • 74열~ 78열 – flipTimer가 값을 보관하고 있는 동안(2장이 모두 앞면이 된후 대기하고 있는 동안)、혹은 이미 앞부분으로 표시0된 카드를 클릭한 경우(「src.textContent != “”」)는、아무것도 행하지 않고 returen으로 돌아갑니다.
  • 80열 ~ 82열 – 여기서는 클릭된 카드를 앞면표시로 표시합니다.
  • 84열 ~ 115열 – 카드가 앞면일때 표시할 그림을 선택합니다.
  • 118열 ~ 121열 – 「prevCard == null 」이 성립할 경우、즉、현재 클릭한 카드가 1장째일 경우는, 현재 클릭한 카드를 prevCard에 대입하여 return으로 함수부터 나옵니다. 2장째 카드 의 클릭을 기다리기 위해서 입니다.
  • 124열 ~ 129열 – 2장째카드를 클릭 하였을때, 1장째와 똑같은 카드일 경우에 행하는 처리입니다. 선택한 카드가 10장째일 경우 카드는 전부 앞면을 향해 있으므로 경과시간을 계측하는 timer는 멈추게 됩니다. 2장의 카드가 모두 같으므로, prevCard에 null을 대입함과 동시에(=선택한 1장째의 카드 클리어)、잘못 선택했을때 원래대로 돌리는 타이머인 flipTimer를 정지 시킵니다.
  • 130열 ~ 140열 – 2장째카드를 클릭 하였을때, 1장째와 다른 카드일 경우에 행하는 처리입니다. 1초후에 무명함수를 실행합니다. 즉, 1초 동안 두개의 숫자가 표시되는 상태가 됩니다. 무명함수 안에서는 1장째의 카드 prevCard와 2장째의 카드에 대해서、className에서의 스타일을 적용시키고, textContent에 빈 문자를 대입함으로서 원래대로 돌아가며 처리는init()함수로 부터 시작하게 됩니다.

일러스트레이터

대해원님으로 부터 이미지를 받았습니다!
덕분에 좋은 게임이 완성 돼었습니다!

Web게임개발

사이트 메인

프로그래밍 메인