분류 javascript

자바스크립트 게임 - 무지개를 찾아라

컨텐츠 정보

  • 조회 183 (작성일 )

본문

"일부 CSS와 일반 JavaScript로 약간의 게임을 만들었습니다. 게임은 CSS Grid + Flexbox를 통해 완벽하게 반응합니다. 무지개는 항상 다른 장소에 숨겨져 있기 때문에 원하는 만큼 여러 번 재생할 수 있습니다"– ilithya.


https://codepen.io/ilithya/pen/vodGee 


HTML : 



<main class="game">
  <div class="game__canvas">
    <div class="box" id="play-box">
      <div class="box__inner">
        <h1 class="box__headline">Find the rainbow</h1>
        <p class="box__txt">Press (click/tap) the buttons until you find it!</p>
        <button class="box__btn p-btn" type="button" id="play-btn">Play now</button>
      </div>
    </div>
    <div class="grid">
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
      <div class="grid__cell">
        <button class="grid__btn p-btn" type="button"> <span class="grid__btn__rainbow"> </span></button>
      </div>
    </div>
  </div>
</main>



CSS : 


html,
body {
  height: 100%;
}

body {
  min-width: 20em;
  background-color: pink;
  margin: 0;
  padding: 0;
}

::-moz-selection {
  background-color: pink;
}

::selection {
  background-color: pink;
}

.p-btn {
  cursor: pointer;
  outline: none;
  -webkit-tap-highlight-color: transparent;
}

.game {
  width: 100%;
  height: 100%;
  display: flex;
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
}
.game__canvas {
  width: 100%;
  height: auto;
  max-width: 500px;
  margin: auto;
  position: relative;
}

.box {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 120;
}
.box__inner {
  width: 100%;
  height: auto;
  background-color: blue;
  box-sizing: border-box;
  color: yellow;
  font-family: 'Overpass Mono', monospace;
  padding: 2.2rem 1.5rem;
  position: absolute;
  top: 22%;
  text-align: center;
}
.box__headline {
  font-size: 2rem;
  line-height: 1;
  margin: 0;
}
.box__txt {
  font-size: 0.9rem;
}
.box__btn {
  background-color: yellow;
  color: blue;
  font-family: 'Overpass Mono', monospace;
  font-size: 1rem;
  font-weight: bold;
  line-height: 1;
  padding: 0.5rem 1rem;
  text-transform: lowercase;
}

.grid {
  display: grid;
  place-items: center;
  justify-content: center;
  grid-template-columns: repeat(auto-fit, 100px);
}
.grid__cell {
  width: 100px;
  height: 100px;
}
.grid__btn {
  width: 60%;
  height: 60%;
  background-color: yellow;
  border: 4px solid blue;
  line-height: 1.5;
  margin: 13% 26%;
  position: relative;
  transition: all 0.05s ease-in;
}
.grid__btn.is-pressed {
  background-color: blue;
  cursor: default;
  -webkit-transform: translate(calc(-10% + 1px), calc(10% - 1px));
          transform: translate(calc(-10% + 1px), calc(10% - 1px));
}
.grid__btn.is-pressed::before {
  width: 10%;
}
.grid__btn.is-pressed::after {
  height: 10%;
}
.grid__btn::before, .grid__btn::after {
  border: 4px solid blue;
  content: '';
  background: yellow;
  position: absolute;
  transition: all 0.05s ease-in;
}
.grid__btn::before {
  width: 20%;
  height: calc(100% + 2px);
  border-right: 0;
  border-bottom-width: 2px;
  -webkit-transform: skew(0deg, -45deg) translateX(-4px);
          transform: skew(0deg, -45deg) translateX(-4px);
  -webkit-transform-origin: top right;
          transform-origin: top right;
  top: -8px;
  right: 99%;
}
.grid__btn::after {
  width: calc(100% + 1px);
  height: 20%;
  border-top: 0;
  border-left-width: 3px;
  -webkit-transform: skew(-45deg, 0deg) translateY(4px);
          transform: skew(-45deg, 0deg) translateY(4px);
  -webkit-transform-origin: top right;
          transform-origin: top right;
  top: 100%;
  right: -8px;
}
.grid__btn__rainbow {
  position: absolute;
  top: 40%;
  left: 40%;
  z-index: 90;
  font-size: 0;
}
.grid__btn__rainbow.has-rainbow {
  -webkit-animation: rainbowFound 1s ease-in-out alternate infinite;
          animation: rainbowFound 1s ease-in-out alternate infinite;
  font-size: 28px;
}

@-webkit-keyframes rainbowFound {
  0% {
    -webkit-transform: translate(-11.1111111111px, -11.1111111111px);
            transform: translate(-11.1111111111px, -11.1111111111px);
  }
  25% {
    font-size: 6rem;
    -webkit-transform: translate(-45.4545454545px, -55.5555555556px) rotate(25deg);
            transform: translate(-45.4545454545px, -55.5555555556px) rotate(25deg);
  }
  50% {
    font-size: 6rem;
    -webkit-transform: translate(-45.4545454545px, -55.5555555556px) rotate(-15deg);
            transform: translate(-45.4545454545px, -55.5555555556px) rotate(-15deg);
  }
  75% {
    font-size: 6rem;
    -webkit-transform: translate(-45.4545454545px, -55.5555555556px) rotate(25deg);
            transform: translate(-45.4545454545px, -55.5555555556px) rotate(25deg);
  }
  100% {
    font-size: 6rem;
    -webkit-transform: translate(-45.4545454545px, -55.5555555556px) rotate(-15deg);
            transform: translate(-45.4545454545px, -55.5555555556px) rotate(-15deg);
  }
}

@keyframes rainbowFound {
  0% {
    -webkit-transform: translate(-11.1111111111px, -11.1111111111px);
            transform: translate(-11.1111111111px, -11.1111111111px);
  }
  25% {
    font-size: 6rem;
    -webkit-transform: translate(-45.4545454545px, -55.5555555556px) rotate(25deg);
            transform: translate(-45.4545454545px, -55.5555555556px) rotate(25deg);
  }
  50% {
    font-size: 6rem;
    -webkit-transform: translate(-45.4545454545px, -55.5555555556px) rotate(-15deg);
            transform: translate(-45.4545454545px, -55.5555555556px) rotate(-15deg);
  }
  75% {
    font-size: 6rem;
    -webkit-transform: translate(-45.4545454545px, -55.5555555556px) rotate(25deg);
            transform: translate(-45.4545454545px, -55.5555555556px) rotate(25deg);
  }
  100% {
    font-size: 6rem;
    -webkit-transform: translate(-45.4545454545px, -55.5555555556px) rotate(-15deg);
            transform: translate(-45.4545454545px, -55.5555555556px) rotate(-15deg);
  }
}


Javascript : 


/* FIND THE RAINBOW
 * Press (click/tap) the buttons until you find the rainbow!
 * Game is fully responsive via CSS Grid + Flexbox. 
 * 
 * You can play as many times as you'd like, because the rainbow it's always hidden in a different place.
 *
 * Feel free to improve this game, or give me feedback.
 *
 * #006 - #100DaysOfCode
 * By ilithya | 2019
 */
let gameOver = false;
const rainbowString = "rainbow";
const btnPressClass = "is-pressed";
const rainbowClass = "has-rainbow";

const dialog = {
  hide: function (dialogBox) {
    dialogBox.style.display = "none";
  },
  updateContent: function () {
    const boxHeadline = document.querySelector("#play-box .box__headline");
    boxHeadline.innerHTML = "Play again?";

    const boxText = document.querySelector("#play-box .box__txt");
    boxText.innerHTML = "Rainbow is never in the same place.";
  },
  showPlayAgain: function (dialogBox) {
    dialog.updateContent();
    dialogBox.style.display = "block";
  } };


const getRandomIntInclusive = maxNum => {
  const min = 0;
  const max = Math.floor(maxNum);

  return Math.floor(Math.random() * (max - min + 1)) + min;
};

const rainbow = {
  insert: function (el) {
    const btnCount = el.length - 1;
    const luckyBtn = getRandomIntInclusive(btnCount);

    el[luckyBtn].children[0].innerHTML = rainbowString;
    el.forEach(function (item) {
      game.addBtnClick(item);
    });
  },
  remove: function (el) {
    el.forEach(function (item) {
      const itemChild = item.children[0];
      itemChild.innerHTML = "";
      itemChild.classList.remove(rainbowClass);
      item.classList.remove(btnPressClass);
    });
  } };


const game = {
  btn: document.querySelectorAll(".grid__btn"),
  box: document.getElementById("play-box"),
  start: function () {
    rainbow.insert(game.btn);
    dialog.hide(game.box);
  },
  run: function () {
    if (gameOver) {
      rainbow.remove(game.btn);
      game.start();
    } else {
      game.start();
    }
  },
  stop: function () {
    gameOver = true;

    game.btn.forEach(function (item) {
      game.removeBtnClick(item);
    });

    setTimeout(function () {
      dialog.showPlayAgain(game.box);
    }, 5000);
  },
  play: function (e) {
    const thisItem = e.target;
    thisItem.classList.add(btnPressClass);
    game.removeBtnClick(thisItem);

    const rainbowEl = thisItem.children[0];
    if (rainbowEl.innerHTML === rainbowString) {
      rainbowEl.classList.add(rainbowClass);
      game.stop();
    }
  },
  addBtnClick: function (el) {
    el.addEventListener("click", game.play, false);
  },
  removeBtnClick: function (el) {
    el.removeEventListener("click", game.play, false);
  } };


const btnPlay = document.getElementById("play-btn");
btnPlay.addEventListener("click", game.run, false);