Giant Danio Fish
본문 바로가기
Javascript_Effect

게임 이펙트 - 같은 그림 찾기

by 코딩왕자 2022. 10. 29.

게임 효과

게임 이펙트 - 같은 그림 찾기

오늘은 같은그림찾기 게임을 만들어보겠습니다. 핑크색 메모리 문서를 클릭해보세요!


결과


HTML 작성

게임판을 만들 틀을 잡아줍니다. 같은사진을 앞뒤로 쓸것이기에 li태그 안에 div태그를 두개를 만들어줍시다.

소스 보기
<div class="memory__wrap">
    <div class="memory__inner">
        <div class="memory__header">
            <h2>같은그림찾기</h2>
            <div class="memory__box">
                <ul>
                    <li>1. 기회는 세번입니다.</li>
                    <li>2. 한번 맞출때 마다 1점씩 올라갑니다.</li>
                    <li>3. 제한시간은 없으니 천천히 푸시기 바랍니다.</li>
                    <li>4. 마음의 준비를 하신 뒤 시작버튼을 눌러주세요.</li>
                </ul>
                <div class="start">시작</div>
            </div>  
        </div>
        <div class="memory__card">
            <div class="card__header">
                <p>틀린 횟수 : <span class="chance">0</span> 맞힌 개수 : <span class="score"> 0 </span>개</p>
            </div>                
            <ul class="cards">
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon01.png" alt="icon1">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon02.png" alt="icon2">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon03.png" alt="icon3">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon04.png" alt="icon4">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon05.png" alt="icon5">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon06.png" alt="icon6">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon07.png" alt="icon7">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon08.png" alt="icon8">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon01.png" alt="icon1">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon02.png" alt="icon2">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon03.png" alt="icon3">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon04.png" alt="icon4">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon05.png" alt="icon5">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon06.png" alt="icon6">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon07.png" alt="icon7">
                    </div>
                </li>
                <li>
                    <div class="view front">
                        <img src="../assets/img/memory_icon.png" alt="icon">
                    </div>
                    <div class="view back">
                        <img src="../assets/img/memory_icon08.png" alt="icon8">
                    </div>
                </li>
            </ul>
            <!-- memory__card -->
        </div>
        <div class="memory__result">
            <div class="result">게임 오버</div>
            <!-- 맞힌 개수 :<span class="resultScore">개</span> -->
            <div class="result__restart">다시 시작하기</div>
        </div>
        <div class="memory__clear">           
            <div class="clear">게임 승리</div>
            틀린 개수 : <span class="clearScore"> 0개</span>
            <!-- <div class="clear__restart">다시 시작하기</div> -->
        </div>
    </div>
</div>

CSS 작성

같은그림찾기 CSS

소스 보기
.memory__wrap {
    position: relative;
}
.memory__inner {
    display: none;
    width: 600px;
    height: 615px;
    border: 3px solid #08f;
    background: #000;
    position: absolute;
    left: 300px;
    top: 100px;
    border-radius: 20px;
    animation: flicker 1.5s infinite alternate;
}
.memory__inner.show {
    display: block;
    overflow: hidden;
}
.memory__header {
    width: 100%;
    height: 100%;
    z-index: 2;
    background: linear-gradient( to bottom, rgba(255, 255, 0, 0.5), rgba(0, 0, 255, 0.5));
}
.memory__header h2 {
    font-size: 60px;
    padding-top: 100px;
    text-align: center;
    color: #fff;
    padding-bottom: 50px;
    box-sizing: border-box;
}
.memory__header .memory__box {}
.memory__header .memory__box li {
    text-align: center;
    color: #fff;
    line-height: 1.5;
    font-size: 25px;
}
.memory__header .start {
    margin-top: 150px;
    text-align: center;
    font-size: 50px;
    cursor: pointer;
    box-sizing: border-box;
    color: #fff;
}
.memory__header .start:hover {
    color: rgba(255, 255, 0, 0.5);
}
.memory__result, .memory__clear {
    display: none;
}
.memory__clear.show, .memory__result.show {
    display: block;
    position: absolute;
    left: 25%;
    top: 25%;
    width: 50%;
    height: 50%;
    z-index: 100;
    background: linear-gradient( to bottom, rgba(255, 255, 0, 1), rgba(0, 0, 255, 1));
    border-radius: 15px;
    font-size: 20px;
    text-align: center;
}
.clearScore {
    display: inline-block;
    margin-bottom: 15px;
    color: blue;
}
.resultScore {
    display: inline-block;
    margin-bottom: 15px;
    color: red;
}
.memory__result .result {
    display: block;
    text-align: center;
    padding-top: 35px;
    font-size: 50px;
    color: red;
    margin-bottom: 70px;
}
.memory__clear .clear {
    display: block;
    text-align: center;
    padding-top: 35px;
    font-size: 50px;
    color: blue;
    margin-bottom: 70px;
}
.memory__result .result__restart, .memory__clear .clear__restart {
    text-align: center;
    font-size: 20px;
    border-radius: 20px;
    background: #fff;
    color: #000;
    padding: 5px 10px;
    margin-top: 10px;
    width: 150px;
    margin: 0 auto;
}
.memory__result .result__restart:hover, .memory__clear .clear__restart:hover {
    background: #000;
    color: #fff;
}
.card__header {
    display: flex;
    justify-content: space-between;
}
.card__header .chance {
    margin-right: 100px;
}
.time span {
    color: #fff;
}
.memory__card {
    padding: 40px;
}
.memory__card p {
    text-align: center;
    color: #fff;
    margin-bottom: 15px;
}
.memory__card .cards {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    padding-bottom: 15px;
    box-sizing: border-box;
}
.memory__card .cards li {
    list-style: none;
    width: 120px;
    height: 120px;
    position: relative;
    transform-style: preserve-3d;
    perspective: 500px;
}
.memory__card .cards li img {
    width: 100%;
    box-sizing: border-box;
    padding: 15px;
}
.memory__card .cards li .view {
    position: absolute;
    width: 100%;
    height: 100%;
    background: #08f;
    backface-visibility: hidden;
    padding: 10px;
    border-radius: 20px;
    transition: all 0.5s;
    /* user-select: none; */
    pointer-events: none;
}
.memory__card .cards li .front {
    transform: rotateY(0deg);
}
.memory__card .cards li.flip .front {
    transform: rotateY(180deg);
}
.memory__card .cards li .back {
    transform: rotateY(-180deg);
}
.memory__card .cards li.flip .back {
    transform: rotateY(0deg);
}
.memory__card .cards li.shakeX {
    animation: shakeX 1s 1;
}
.memory__card .cards li.shakeY {
    animation: shakeY 1s 1;
}
@keyframes flicker {
    0%,
    19%,
    21%,
    23%,
    25%,
    54%,
    56%,
    100% {
        box-shadow: 0 0 0.5rem #fff, inset 0 0 0.5rem #fff, 0 0 2rem #08f,
        inset 0 0 2rem #08f, 0 0 4rem #08f, inset 0 0 4rem #08f;
    }
}

@keyframes shakeX {
    from,
    to {
        transform: translate3d(0, 0, 0);
    }
  
    10%,
    30%,
    50%,
    70%,
    90% {
      transform: translate3d(-10px, 0, 0);
    }
  
    20%,
    40%,
    60%,
    80% {
      transform: translate3d(10px, 0, 0);
    }
}

@keyframes shakeY {
    from,
    to {
        transform: translate3d(0, 0, 0);
    }

    10%,
    30%,
    50%,
    70%,
    90% {
        transform: translate3d(0, -10px, 0);
    }

    20%,
    40%,
    60%,
    80% {
        transform: translate3d(0, 10px, 0);
    }
}

JS 작성

버튼 스크립트

시작버튼, 게임을 클리어했을 때, 게임을 패배했을 때 시작하는 함수를 만들어봅시다

<script>
    // 시작버튼 클릭
    startBtn.addEventListener("click",() => {
        memoryFront.style.display="none";
        shuffleCard()
    })

    let cardOne, cardTwo;

    let disableDeck = false;
    let matchedCard = 0;
    let missedCard = 0;
    let sound = [
        "../assets/audio/Success.m4a",
        "../assets/audio/fail.mp3",
        "../assets/audio/up.mp3"
    ]

    // 재시작버튼 클릭
    resultRestart.addEventListener("click", ()=>{
        memoryResult.classList.remove("show")
        shuffleCard()
    })

    // 재시작버튼 클릭
    clearRestart.addEventListener("click", ()=>{
        memoryClear.classList.remove("show")
        shuffleCard()
    })
</script>

카드 뒤집기 함수

카드를 클릭하면 카드의 이미지 src 주소를 가져오도록 만들었습니다. flip이라는 클래스를 추가해서 미리 만들어놓은 css로 카드가 뒤집어지는 효과를 주고, 카드1의 이미지 src와 카드2의 이미지 src를 비교하는 함수는 밑에서 설명드리겠습니다.

<script>
    let cardOne, cardTwo;

    let disableDeck = false;
    let matchedCard = 0;
    let missedCard = 0;
    let sound = [
        "../assets/audio/Success.m4a",
        "../assets/audio/fail.mp3",
        "../assets/audio/up.mp3"
    ]

    // 카드 뒤집기
    function flipCard(e){
        let clickedCard = e.target;

        if(clickedCard !== cardOne && !disableDeck){
            clickedCard.classList.add("flip");

            // 카드1이 아니면 카드1값에 clickCard넣기
            if(!cardOne){
                return cardOne = clickedCard;
            }        
            cardTwo = clickedCard;
            disableDeck = true;
            // 결국 카드1, 카드2 클릭하면 matchCard로 두개의 이미지 src값만 나오게 설정


            let cardOneImg = cardOne.querySelector(".back img ").src;
            let cardTwoImg = cardTwo.querySelector(".back img ").src;

            matchCards(cardOneImg, cardTwoImg)
        }

        // console.log(cardOneImg)
        // console.log(cardTwoImg)
    }
</script>

두개의 이미지 비교하는 함수

img1과 img2가 같은경우 매치카드가 1씩 올라가고 8이되면 게임이 끝나도록 설정했습니다. img1과 img2는 flipcard에서의 cardOneImg, cardTwoimg 를 받아옵니다. img1과 img2가 다를경우 좌우로 움직이는 효과를 주었습니다.

<script>
    // 카드 확인(두개의 이미지 비교)
    function matchCards(img1, img2){
        if(img1 == img2){
            // 같을 경우
            matchedCard++;
            memoryScore.innerText = matchedCard;

            // 정답맞춘 오디오
            soundMatch.play();

            if(matchedCard == 8){
                // alert("게임 오버")
                soundSuccess.play();

                memoryClear.classList.add("show");

            }
            // 이벤트 제거하고 초기화하는 과정
            cardOne.removeEventListener("click", flipCard);
            cardTwo.removeEventListener("click", flipCard);
            cardOne = cardTwo = "";
            disableDeck = false;
        } else {
            missedCard++;
            
            // 일치하지 않는 경우(틀린음악, 이미지가 좌우로 흔들림)
            setTimeout(()=>{
                cardOne.classList.add("shakeX");
                cardTwo.classList.add("shakeX");
                // 틀렸을때 음악재생
                soundUnMatch.play();
                chance.innerText = missedCard + "회";
            }, 500);
            
            setTimeout(()=>{
                cardOne.classList.remove("shakeX", "flip");
                cardTwo.classList.remove("shakeX", "flip");

                cardOne = cardTwo = "";
                disableDeck = false;

                if(missedCard == 3){
                    // alert("gameover")
                    memoryResult.classList.add("show")                
                }
            }, 1500)

            
        }
    }
</script>

초기화 하는 함수

설정한 바뀌는값들을 모두 기본값으로 되돌리고, 카드의 셔플하는 위치는 random과 sort메서드를 이용해서 랜덤으로 설정되도록 하였습니다. 또한 settime아웃으로 0.2초 간격으로 카드를 하나씩 보여준뒤 4초후에 모든 카드를 다시 뒤집어줍니다.

<script>
    // 카드 섞기
    function shuffleCard(){
        // 초기화
        cardOne = cardTwo = "";
        disableDeck = false;
        matchedCard = missedCard = 0;
        disableDeck = false;
        memoryScore.innerText = matchedCard;
        chance.innerText = missedCard;
        

        let arr = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8];

        // 0.5보다 큰경우 1 아닌경우 -1
        let result = arr.sort(() => Math.random() > 0.5 ? 1 : -1);

        memoryCards.forEach((card, index) => {
            card.classList.remove("flip");
            
            setTimeout((e)=>{
                card.classList.add("flip");
            }, 200 * index);

            setTimeout(()=> {
                card.classList.remove("flip");
                card.classList.remove("shakeX");
            }, 4000)

            let ImgTag = card.querySelector(".back img");
            ImgTag.src = `../assets/img/memory_icon0${arr[index]}.png`
        })
    }
</script>

댓글


광고 준비중입니다