이로
짝 맞추기 게임 만들기 본문
카드 8장으로 4x4 짝 맞추기 게임 만들기 입니다. 외적인 요소는 신경쓰지 않고 코드만 작성하였습니다.
초보 코더입니다. 수정할 사항이나 더 나은 방법이 있으면 조언 부탁드리겠습니다.
아이디어
코딩 전 계획 세우기
1. 테이블에 이미지 배치하고 script에서 th와 img의 정보를 읽어오기
1.1 th의 id는 맞 춘카드, 못 맞춘카드 구분하는 용도이며 img의 id는 같은카드인지 아닌지 확인하는 용도로 설정
2. 각 버튼 구현하기
주의할점
2.1 정답보기 버튼 : 어떠한 상황에서도 정답보기 버튼 클릭시 정답 공개
2.2 뒷면 보이기 버튼 : 게임 도중에 뒷면보이기 버튼 클릭 불가능하게 하기
2.3 섞기 버튼 : 게임 도중에 섞지 못하게 하기
2.4 재시작 버튼 : 언제든 재시작 할 수 있어야 한다. 게임 중 재시작 버튼 누를 수 있다.
1) 모든 카드 뒤집기
2) 섞기
3) 맞췄을 때 th의 id=1된거 초기화해주기
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
/* 카드 이미지 사이즈 조절 */
img {
width: 200px;
height: 270px;
opacity: 0.7;
}
</style>
</head>
<body>
<!-- 1. 버튼 4개(정답보기, 뒷면 보이기, 섞기, 재시작) 만들기 -->
<button id='back1'>정답보기</button> <!-- 앞면 보이기-->
<button id='back2'>뒷면 보이기</button><!-- 뒷면 보이기-->
<button id='shuffle'>섞기</button><!-- 섞기-->
<button id='restart'>재시작</button><!-- 재시작-->
<!-- 2. 테이블 만들고, 초기 카드 배치하자 -->
<!-- 2.1 카드 초기 배치시 52장 모두 넣지말고, 8장 골라서 2번씩 배치해 16장으로 게임 진행하게 하자. -->
<!-- 2.2 th의 id=0 - 못맞춘 카드, id=1 맞춘 카드 -->
<!-- 2.3 img의 id- 같은 카드 구별하는 숫자 -->
<table style="width: 800px; height: auto;">
<tr>
<th id=0>
<img src="s1.png" alt="0" id="1">
</th>
<th id=0>
<img src="s1.png" alt="0" id="1">
</th>
<th id=0>
<img src="h1.png" alt="0" id="2">
</th>
<th id=0>
<img src="h1.png" alt="0" id="2">
</th>
</tr>
<tr>
<th id=0>
<img src="d1.png" alt="0" id="3">
</th>
<th id=0>
<img src="d1.png" alt="0" id="3">
</th>
<th id=0>
<img src="c1.png" alt="0" id="4">
</th>
<th id=0>
<img src="c1.png" alt="0" id="4">
</th>
</tr>
<tr>
<th id=0>
<img src="s2.png" alt="0" id="5">
</th>
<th id=0>
<img src="s2.png" alt="0" id="5">
</th>
<th id=0>
<img src="h2.png" alt="0" id="6">
</th>
<th id=0>
<img src="h2.png" alt="0" id="6">
</th>
</tr>
<tr>
<th id=0>
<img src="d2.png" alt="0" id="7">
</th>
<th id=0>
<img src="d2.png" alt="0" id="7">
</th>
<th id=0>
<img src="c2.png" alt="0" id="8">
</th>
<th id=0>
<img src="c2.png" alt="0" id="8">
</th>
</tr>
</table>
<!--
* 클릭시 테이블 내용 바뀌게하려면? -> script에서 th를 불러와서 th끼리 순서 바꿔보자
* html 에서 같은 테이블에 이미지 A,B 두 장 저장해놓고 A는 보이기 B는 안보이기 를 설정할 수 있나?
백그라운드에 앞면, 얹는 이미지에 뒷면 해볼까? -->
<script>
window.onload = function () {
var th = document.getElementsByTagName('th');
var img = document.getElementsByTagName('img'); // 이미지
var bk1 = document.getElementById('back1'); // 앞면 보이기
var bk2 = document.getElementById('back2'); // 뒷면 보이기
var sf = document.getElementById('shuffle'); // 섞기
var restart = document.getElementById('restart'); // 섞기
var sfDeck = {}; // 섞은 덱 저장할 곳
var frflag;// 카드 앞면시 true
var bkflag;// 카드 뒷면시 true
var playGame;// 게임진행중 뒷면 클릭 못하게하기 게임진행은 카드 클릭 시작한 순간부터 시작.
var matchTest = new Array(); // 카드 매칭 테스트시 사용할 배열
var clickAble; // 카드 2장 클릭시 틀렸을 때, 다른카드들 클릭 못하게 한다.
saveDeck(th); // 처음 로딩시 기본덱 저장하기. (안하면 첫 버튼을 앞면 보이기 클릭시 오류)
gameStart();
// ========== /게임 재시작 ==========
restart.onclick = function () { // 카드 뒤집고, 카드덱 데이터를 셔플하기
playGame = false;
resetId();
flipCard();
shuffle2();
}
// ========== 게임시작 함수 ==========
function gameStart() {
shuffle(th); // 앞면인 상태에서 셔플
saveDeck(th); // 셔플한 덱 저장
flipCard(); // 카드 뒤집기
resetId();
}
// ========== /카드 이미지 클릭 ==========
// 카드 클릭시 게임 시작 및 카드 뒤집기
for (let i = 0; i < th.length; i++) {
th[i].onclick = function () {
if (th[i].id == "1") { return; }
// alt값이 1인카드는 맞춘카드이므로 아래로 진행하지 못하게 한다.
if (matchTest[0] != th[i] && (bkflag) && clickAble) {
// 같은카드 두번 클릭한 것 아니고 게임이 시작되어 뒷면보이기 클릭한 상태일 때
// 진행된다.
playGame = true;
matchflag = false;
th[i].innerHTML = sfDeck[i]; // th하나 클릭 시 뒤집게하는데,
//i번째의 sfDeck를 보이게한다.
matchTest.push(th[i]);
matchT();
gameEndTest();
}
}
}
// ---- 오류
// 같은 카드 찾아서 처음 클릭시 앞면 유지, 그러나 한번 더 클릭하면 다시 뒷면으로 바뀐다.
// --> 같은카드 클릭시 아무 작업 못하게 하자
// 앞면에서 클릭시 뒷면으로 바뀐다. -> 뒷면인 상태에서 진행하게 하자.
// ========== -모두 매칭시 게임종료 안내문구- ==========
function gameEndTest() {
let cnt = 0;
for (let i = 0; i < th.length; i++) {
if (th[i].id == "1") {
cnt++;
}
if (th.length == cnt) {
setTimeout(function () { alert('게임이 종료되었습니다.'); }, 1000)
}
}
}
// ========== -카드 이미지 클릭- ==========
function resetId() { // 앞면보이기 클릭시 th의 id들 0으로 초기화해주기
for (let i = 0; i < th.length; i++) {
th[i].id = "0";
}
}
// ========== /카드 매칭테스트 ==========
function matchT() {
if (matchTest.length == 2) {
if ((matchTest[0].childNodes[1].id) == (matchTest[1].childNodes[1].id)) {
//img의 id로 맞춘 숫자카드인지 검사
matchTest[0].id = "1"; // th의 id 0 - 아직 못 맞춘 카드, 1- 맞춘 카드
matchTest[1].id = "1";
matchTest = new Array();
return;
} else {//다른숫자카드}
// 하나 클릭 시 뒤집으면 뒤집는동안 아무 작업 못하게 해야한다.
clickAble = false;
// 일정 시간 지난 뒤 다시 back 화면이 표시되게 한다.
setTimeout(function () {
matchTest[0].innerHTML = '<img src="back.jpg" alt="0" id="0">';
matchTest[1].innerHTML = '<img src="back.jpg" alt="0" id="0">';
matchTest = new Array();
clickAble = true;
}, 1000)
}
}
}
// ---- 오류
// 하나 뒤집고 시간 텀 내서 뒤집으면 앞면이 계속 표시된다.
//--> 하나 클릭 시 다 뒤집힐 때 까지 아무 작업 못하게 하자
// ========== /정답보기 버튼 ==========
bk1.onclick = function () {
if (bkflag && clickAble) {// 게임 시작전에는 섞기만 가능하며, 뒷면인 상태여야만
//앞면을 볼 수 있다. 클릭 모션이 종료된 후에만 답을 볼 수 있게 한다.
for (let i = 0; i < th.length; i++) { // '정답 보기' 클릭시 카드 앞면 보이게하기
th[i].innerHTML = sfDeck[i];
}
resetId()
bkflag = false;
frflag = true;
playGame = false; // 정답을 봤으므로 게임포기로 간주한다.
}
}
// ---- 오류
// 뒷면 보이기 상태에서 카드 2장을 시간 조금 두고 클릭 한 뒤, 한장이 뒤집어진 상태에서
//정답보기 클릭시 앞면이 뒷면으로 변한다.
// ========== /뒷면 보이기 버튼 ==========
bk2.onclick = function () {
if (!playGame) { flipCard(); } // 게임 진행중에 뒷면으로 못바꾸게하기. 게임 포기하려면
//앞면보기 누르게하기.
}
// ========== /카드 뒤집기 ==========
function flipCard() {
for (let i = 0; i < th.length; i++) {
th[i].innerHTML = '<img src="back.jpg" alt="" id="0">';
}
bkflag = true;
frflag = false;
clickAble = true;
}
// ========== /섞기 버튼 ==========
sf.onclick = function () {
if (!playGame) { // 게임 진행중에는 섞지못하게하기
if (bkflag) {
shuffle2(); // 뒤집은 상태에서 셔플
} else {
shuffle(th); // 앞면인 상태에서 셔플
saveDeck(th); // 셔플한 덱 저장
}
}
}
// ---- 오류
// 현재 뒷면 보이기 클릭시 섞기 안된다. 섞기는 모두 뒷면일때, 또는 모두 앞면일때 섞게 하자.
//--> play게임일 때 섞기 버튼 가능하게 하자.
// ========== /뒤집은 상태에서 섞기 ==========
function shuffle2() {
var c = 0;
for (let i = 0; i < th.length; i++) {
c = Math.floor(Math.random() * (th.length));
let tmp = sfDeck[0];
sfDeck[0] = sfDeck[c];
sfDeck[c] = tmp;
}
}
// ---- 오류
// 뒷면에서 섞을 경우 문제다. 뒷면에서 섞기 버튼 누르면 뒷면 유지한 상태에서
// 임시저장덱만 섞자.
// ========== /앞면 상태에서 섞기 ==========
function shuffle(ac) {
var c = 0;
for (let i = 0; i < ac.length; i++) {
let tmp = ac[0].innerHTML
c = Math.floor(Math.random() * (ac.length))
ac[0].innerHTML = ac[c].innerHTML
ac[c].innerHTML = tmp;
}
}
// ========== /섞은 덱 저장하기 ==========
function saveDeck(ac) {
for (let i = 0; i < ac.length; i++) {
sfDeck[i] = (ac[i].innerHTML)
}
playGame = false;
frflag = true;
bkflag = false;
}
}
</script>
</body>
</html>
190619 덧)
1. id는 유일하지않아도 프로그램은 잘 돌아가지만, 관례상 유일해야 한다고합니다.
2. 테이블로 만드는것도 좋은 방법이지만 div로 만들어서 img를 추가하는 방법을 고민해보라고 하셨습니다.
3. JS로 만든 뒤, jQuery로 바꿔 보라고 하셨습니다.
그리하여 다시 코딩해보았습니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
/* 카드 이미지 사이즈 조절 */
img {
width: 200px;
height: 270px;
opacity: 0.7;
}
.card {
display: inline-block;
/* width: 200px;
height: auto;
/* margin: 10px; */
}
</style>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
</head>
<body>
<!-- 1. 버튼 4개(정답보기, 뒷면 보이기, 섞기, 재시작) 만들기 -->
<button id='back1'>정답보기</button> <!-- 앞면 보이기-->
<button id='back2'>뒷면 보이기</button><!-- 뒷면 보이기-->
<button id='shuffle'>섞기</button><!-- 섞기-->
<button id='restart'>재시작</button><!-- 재시작-->
<!-- <button id='hint' onclick="hint()">Hint</button>Hint -->
<div class=; id="board" style="width: 900px; height: auto">
</div>
<script>
// ==================== board 구성하기 ====================
var cardArr = [];
var backCard = '<img src="back.jpg" alt="" id="0">';
var tmp = '';
// 배열 만들어서 카드 먼저 배치해놓고, 배열만 섞어서 제공하게하자.
// cardArr에 이미지 소스들 집어넣기
for (let i = 1; i <= 8; i++) {
// board에 넣을 img src를 배열에 넣기
cardArr.push('<div data-state="0" class="card"><img src="' + i + '.png" alt="" data-num="' + i + '" ></div>');
cardArr.push('<div data-state="0" class="card"><img src="' + i + '.png" alt="" data-num="' + i + '" ></div>');
// 화면에 넣을 이미지 주소 복사하기
tmp += '<div data-state="0" class="card"><img src="' + i + '.png" alt="" data-num="' + i + '" ></div>'
tmp += '<div data-state="0" class="card"><img src="' + i + '.png" alt="" data-num="' + i + '" `></div>'
}
$('#board').html(tmp);
var bkflag;// 카드 뒷면시 true
var playGame;// 게임진행중에 모두 뒷면 클릭 못하게하기 게임진행은 카드 클릭 시작한 순간부터 시작.
var matchTest = new Array(); // 카드 매칭 테스트시 사용할 배열
var clickAble; // 카드 2장 클릭시 틀렸을 때, 다른카드들 클릭 못하게 한다.
// ==================================== start ====================================
$(document).ready(function () { gameStart() })
// ==================================== /게임 재시작 ====================================
$('#restart').click(function () {// 카드 뒤집고, 카드덱 데이터를 셔플하기
gameStart()
})
// ==================================== /정답보기 버튼 ====================================
$('#back1').click(function () {
if (bkflag && clickAble) {// 게임 시작전에는 섞기만 가능하며, 뒷면인 상태여야만 앞면을 볼 수 있다. 클릭 모션이 종료된 후에만 답을 볼 수 있게 한다.
frontCard();
resetId()
}
})
// ---- 오류
// 뒷면 보이기 상태에서 카드 2장을 시간 조금 두고 클릭 한 뒤, 한장이 뒤집어진 상태에서 정답보기 클릭시 앞면이 뒷면으로 변한다.
// ==================================== /앞면 보이기 버튼 ====================================
function frontCard() {
// for (let i = 0; i < $('#board>div').length; i++) {
// $('#board>div').eq(i).html(cardArr[i])
// }
$.each($('#board>div'), function (index) { $('#board>div').eq(index).html(cardArr[i]) })
bkflag = false;
playGame = false; // 정답을 봤으므로 게임포기로 간주한다.
clickAble = false;
}
// ==================================== /뒷면 보이기 버튼 ====================================
$('#back2').click(function () {
if (!playGame) { flipCard(); } // 게임 진행중에 뒷면으로 못바꾸게하기. 게임 포기하려면 앞면보기 누르게하기.
})
// ==================================== /섞기 버튼 ====================================
$('#shuffle').click(function () {
//if문으로 모두 뒷면 or 모두 앞면인 상태일 때 앞or뒷 화면 띄워주게한다.
if (!playGame) { // 게임 진행중에는 섞지못하게하기
shuffle(); // 섞기
if (bkflag) {
flipCard();
} else {
frontCard();
}
}
})
// // ==================================== 게임시작 함수 ====================================
function gameStart() {
playGame = false;
shuffle(); // 셔플
flipCard(); // 카드 뒤집기
resetId();
playGame = true;
}
// // ==================================== -모두 매칭시 게임종료 안내문구- ==================================== // 지금 작업하고있는 곳
function gameEndTest() {
let cnt = 0;
for (let i = 0; i < $('#board>div').length; i++) {
if ($('#board>div').eq(i).attr("data-state") == "1") {
cnt++;
}
if ($('#board>div').length == cnt) {
setTimeout(function () { alert('게임이 종료되었습니다.'); }, 1000)
}
}
}
// // ==================================== div data-num 리셋(카드 앞,뒷면 체크) ====================================
function resetId() { $('#board>div').attr("data-state", "0") }// 앞면보이기 클릭시 th의 id들 0으로 초기화해주기
// // ==================================== /카드 매칭테스트 ====================================
function matchT() {
if (matchTest.length == 2) { //img의 data-num으로 비교 matchTest[0]=$('#board>div').eq(i)인 상태이다.
if (matchTest[0].children().children().attr("data-num") == matchTest[1].children().children().attr("data-num")) { //img의 id로 맞춘 숫자카드인지 검사
matchTest[0].attr("data-state", "1"); // th의 id 0 - 아직 못 맞춘 카드, 1- 맞춘 카드
matchTest[1].attr("data-state", "1");
matchTest = new Array();
return;
} else {//다른숫자카드}
// 하나 클릭 시 뒤집으면 뒤집는동안 아무 작업 못하게 해야한다.
clickAble = false;
// 일정 시간 지난 뒤 다시 back 화면이 표시되게 한다.
setTimeout(function () {
matchTest[0].html(backCard);
matchTest[1].html(backCard);
matchTest = new Array();
clickAble = true;
}, 1000)
}
}
}
// ==================================== /카드 뒤집기 ====================================
function flipCard() {
for (let i = 0; i < $('#board>div').length; i++) {
$('#board>div').eq(i).html(backCard)
}
bkflag = true;
clickAble = true;
}
// // ==================================== 섞기 ====================================
function shuffle() {
cardArr.sort(function (a, b) { return Math.random() - 0.5 });
}
// ==================================== /카드 이미지 클릭 ====================================
// 카드 클릭시 게임 시작 및 카드 뒤집기
for (let i = 0; i < $('#board>div').length; i++) {
$('#board>div').eq(i).click(function () {
if ($('#board>div').eq(i).attr('data-state') == "1") { return; }// alt값이 1인카드는 맞춘카드이므로 아래로 진행하지 못하게 한다.
playGame = true;
matchflag = false;
if (matchTest[0] != $('#board>div').eq(i) && (bkflag) && clickAble) { // 같은카드 두번 클릭한 것 아니고, 게임이 시작되어 뒷면보이기 클릭한 상태 일 때 진행된다.
$('#board>div').eq(i).html(cardArr[i])
matchTest.push($('#board>div').eq(i));
matchT();
gameEndTest();
}
});
}
</script>
</body>
</html>
수정사항
1. jQuery문 사용하지 않은 코드들을 가급적 jQuery문으로 바꿔 사용했습니다.
(for 문도 $.each()로 사용할 수 있다고 하셨는데, 연구해보겠습니다.)
2. 기존 코드는 테이블로 구성했으나, 지금은 div로 구성했습니다.
jQuery문으로 작성하는것이 익숙해지면 편할것 같다는 느낌이 들었습니다.
'컴퓨터 > 과제' 카테고리의 다른 글
JSP 로그인 만들기 + 쿠키를 이용하여 id저장하 (1) | 2019.06.21 |
---|---|
JSP 로그인 요청한 곳으로 가게하기 (0) | 2019.06.21 |
JS 체크박스 만들어보기 (+ jQuery구문으로 바꿔보기) (0) | 2019.06.19 |
JS select의 option 옮기기 (0) | 2019.06.18 |