hacomono TECH BLOG

フィットネスクラブやスクールなどの顧客管理・予約・決済を行う、業界特化型SaaS「hacomono」を提供する会社のテックブログです!

CSS だけでゲームを作ってみた



はじめに

皆さま、こんにちは!
hacomono でエンジニアをやっております「とんと」と申します。
普段の業務ではフロントエンドからバックエンドまで幅広く実装を担当していますが、当の本人はフロントエンドが好きです。
特に CSS が大好きで、街中の看板やロゴを見ると頭の中で CSS を組んだりします。

そんな CSS 大好きな私がお送りする今回のテックブログでは、「 CSS だけでゲームを作ってみた」というタイトルでやっていこうと思います。
割とネタ要素に寄っているので、気軽にみていただければと思います!

作ったもの

今回は「風船割りゲーム」というものを作ってみました。
以下の Codepen でデモが出来ます。
https://codepen.io/KanonTonto/pen/raNMMZb?editors=1100

内容としては 5 つの動く風船をクリックして割るという単純なものですが、 CSS で表現をする上で大事なポイントは以下です。

  • クリックをしたら風船が割れる(割れた状態の画像に切り替わる)
  • 風船が上下に動くアニメーションを実装する
  • 割れたら上下に動くアニメーションが止まる

これらを実現するための手法について解説していきます。

クリックをしたら風船が割れる

風船自体は画像として表示しており、「膨らんでいる状態」と「割れた状態」をそれぞれ画像の表示を切り替えることで、風船が割れた演出を作っています。
この 2 つの状態を切り替えるために Checkbox を使います。

<div>
  <input type="checkbox" id="baloon">
  <label for="baloon">チェックボックスです</label>
</div>


チェックボックスを利用する理由として、 CSS の checked という疑似要素が使えるからです。
例えば、以下のコードはチェックされたらラベルの色が変わる CSS です。

.area > #checkbox:checked + .checkbox-label {
  color: red;
}


これを利用して、風船が膨らんでいる画像と割れている画像の表示を切り替えます。

<div class="area__baloon">
  <input type="checkbox" id="baloon">
  <label class="baloon-image" for="baloon"></label>
</div>
.area__baloon > input {
  display: none;
}
.area__baloon > #baloon + .baloon-image {
  content: /* 膨らんでいる風船の画像 */;
  animation: 3s linear 1s infinite alternate upAndDown;
  animation-play-state: running;
}
.area__baloon > #baloon:checked + .baloon-image {
  content: /* 割れている風船の画像 */;
  animation: 3s linear 1s infinite alternate upAndDown;
  animation-play-state: paused;
}

こうすることによって、クリックによって風船が割れているように見えます。


風船が上下に動くアニメーションを実装する

風船が割れる見た目を作れたところで、次は風船を上下に動かしてみましょう。
CSS でアニメーションを表現する際は keyframes というアットルールを利用します。
keyframes は、各キーフレームにおいて「こういう状態であって欲しい」というものを定義することで動きを表現します。
今回は風船が上下に動いて欲しいので、以下のようなアニメーションを定義します。

@keyframes upAndDown {
  0% {
    transform: translateY(400px);
  }
  50% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(-400px);
  }
}

上記のキーフレームを風船が上下するように表現します。

.area__baloon > #baloon + .baloon-image {
  content: /* 風船の画像 */;
  animation: 3s linear 1s infinite alternate upAndDown;
}

animation の各プロパティについては、以下の動画で詳しく解説がされていますので併せてご覧ください。

これを行うことで、風船が上下に動くアニメーションが完成しました。

割れたら上下に動くアニメーションが止まる

ゲームもかなり完成に近づいてきましたが、もう一手間加えます。
クリックされて風船が割れたら、風船のアニメーションを止めてみます。
これを実現するためには animation-play-state という CSS プロパティを利用します。

.area__baloon > #baloon + .baloon-image {
  content: /* 風船の画像 */;
  animation: 1s linear 1s infinite alternate upAndDown;
  animation-play-state: running; /* コレを追加する */
}
.area__baloon > #baloon:checked + .baloon-image {
  content: /* 風船の画像 */;
  animation: 1s linear 1s infinite alternate upAndDown;
  animation-play-state: paused; /* コレを追加する */
}

これをすることで、クリックされて割れた風船がその場で止まります。

風船を複数並べて難易度を調整する

この時点で 1 つの風船が上下している状態で、クリックをすると風船が割れて止まる動作が完成しました!
あとは風船を横に並べて、風船の上下するアニメーションの速度をバラバラにしたりして難易度を調整します。

<div class="area__baloon">
  <input type="checkbox" id="baloon1">
  <label class="baloon-image" for="baloon1"></label>
</div>
<div class="area__baloon">
  <input type="checkbox" id="baloon2">
  <label class="baloon-image" for="baloon2"></label>
</div>
<div class="area__baloon">
  <input type="checkbox" id="baloon3">
  <label class="baloon-image" for="baloon3"></label>
</div>
.area__baloon:nth-child(1) > #baloon1 + .baloon-image {
  content: /* 風船の画像 */;
  animation: 3s linear 1s infinite alternate upAndDown;
  animation-play-state: running;
}
.area__baloon:nth-child(1) > #baloon1:checked + .baloon-image {
  content: /* 風船の画像 */;
  animation: 3s linear 1s infinite alternate upAndDown;
  animation-play-state: paused;
}
.area__baloon:nth-child(2) > #baloon2 + .baloon-image {
  content: /* 風船の画像 */;
  animation: 1.5s linear 1s infinite alternate upAndDown;
  animation-play-state: running;
}
.area__baloon:nth-child(2) > #baloon2:checked + .baloon-image {
  content: /* 風船の画像 */;
  animation: 1.5s linear 1s infinite alternate upAndDown;
  animation-play-state: paused;
}
.area__baloon:nth-child(3) > #baloon3 + .baloon-image {
  content: /* 風船の画像 */;
  animation: 2s linear 1s infinite alternate upAndDown;
  animation-play-state: running;
}
.area__baloon:nth-child(3) > #baloon3:checked + .baloon-image {
  content: /* 風船の画像 */;
  animation: 2s linear 1s infinite alternate upAndDown;
  animation-play-state: paused;
}


おわりに

今回は CSS を使って風船割りゲームを作ってみました。
この記事でご紹介したアニメーションや checked という疑似要素などは、実際の開発の現場でも役に立つかと思いますので覚えておいて損はないと思います!
CSS は装飾に使われるのがメインですが、とても奥が深く面白い発見がたくさんあると思っています。
この記事を通して CSS の魅力に少しでも浸っていただけたら幸いです。

それでは、今回はこの辺りで記事を終わりにしようと思います。
引き続き hacomono tech blog をお楽しみに!




hacomonoは先日資金調達について発表を行い、採用イベントを多数実施しています!

株式会社hacomonoでは一緒に働く仲間を募集しています。
エンジニア採用サイトや採用ウィッシュリストもぜひご覧ください!