HTMLとCSSだけでミニゲームをつくる
うぇい。
昨日はお酒を飲んで陽気な気分になっていました。
今は厳しい顔をしながら書いています。
今回は Misoca Advent Calendar 2017 の16日目の記事です。
前の記事は
これでした!
merotan ( @renyamizuno_ ) が、HTML と CSS を使って究極の何かを作ったことについて語ってくれるそうです。
究極の何かを作ったので書きます。
HTMLとCSSだけでどこまで出来るか
HTMLとCSSはすごい表現力を秘めているのは皆さんご存知かと思いますが、 その御蔭でわけわからんと思うことも多々ありますね!
で「HTMLとCSSはチューリング完全」という話もあったりする。
まぁあくまでネタくらいに受け取ったほうが良いと思う。たぶん。
とりあえずそれくらい表現力があるわけなのです。
それで色々すごいものがありまして、例えばこれ。
HTMLとCSSだけで書かれている電卓なんですって。
やばくない?
電卓出来るならなんでも出来るでしょ。
と思ってミニゲームを作りました。
HTMLとCSSでミニゲーム
これです!
マークアップは適当&CSSとかclassの命名規則とかも適当!動けば良いんだよ!()
以下のリンクからであそべます。 スタート後、赤い丸をクリックするゲームです。 左上にポイント、右上に制限時間があります。
https://renyamizuno.github.io/minigame-only-css/
あとiframeでも
スマホだと見れないかも。 HTML見てもらえばわかりますが、JSは一ミリもありません。
どうやってうごいているか
いろいろ説明しないといけないところがあるので、個別に書いていこうと思う。
タイマー
ゲーム画面右上のタイマーについてはどうなっているかというと、
<div class="mini-game-timer"> <div class="mini-game-timer__a"> <div> <div>0</div> <div>1</div> <div>2</div> </div> </div><div class="mini-game-timer__b"> <div> <div>0</div> <div>1</div> <div>2</div> <div>3</div> <div>4</div> <div>5</div> <div>6</div> <div>7</div> <div>8</div> <div>9</div> </div> </div> </div>
HTMLはこうなっている。 タイマーで使う数値を全部書いている。
実際にどう数値を動かしているかというと
.mini-game-timer__a, .mini-game-timer__b { display: inline-block; position:relative; overflow: hidden; height: 24px; width: 12px; } .mini-game-timer__a > div, .mini-game-timer__b > div { position: absolute; } .mini-game-timer__a > div { animation: timer-mekuri-a 30s steps(3) 1; } .mini-game-timer__b > div { animation: timer-mekuri-b 10s steps(10) 3; } @keyframes timer-mekuri-a { 0% { top: -48px; } 100% { top: 24px; } } @keyframes timer-mekuri-b { 0% { top: -216px; } 100% { top: 24px; } }
こんな感じ。
animation
をつかって動かしている。
steps
を使うことで、ステップで動かすことが出来るので、それでうまくやっている。
スコア
これの説明が大変。
まず的からかな。
<input id="target1" class="point" type="checkbox"> <!-- .... --> <label class="target" for="target1"></label>
的の構成はこんな感じ。
label
が実際の的になっている。
.target { position: absolute; top: calc(50% - 13px); left: calc(50% - 13px); width: 26px; height: 26px; background: red; border-radius: 50%; } .target[for="target1"] { animation: target1-animation 5s infinite; } #target1:checked ~ .stage--main > [for="target1"] { background: blue; pointer-events: none; } @keyframes target1-animation { 0% { transform: translate(100px, 50px) } 50% { transform: translate(50px, 100px) } 100% { transform: translate(100px, 50px) } }
それでCSSはこんな感じになっている。
的を画面中心において、animation
でtransform
をつかい位置をずらしている。
またlabel
なので、label
のfor
で指定したidの要素と関連付けが出来ることを活かして、checkbox
にチェックが付くようになっている。
それでクリックされた(for
のcheckbox
にチェックが入った)label
に関しては、pointer-events
を使ってクリックが出来ないようにしている。
チェックが入っているかはchecked
という擬似クラスを使うことで確認できる。
それでスコアの表示の部分については、HTMLは大したことないので割愛。
body { counter-reset: score; } .point:checked { counter-increment: score 10; } .mini-game-score::before { content: "Score: " counter(score); }
CSSはこのようになっている。
counter
を使ってスコアを計算している。
画面の遷移
最初の「スタート」をクリックしてから「おわり」までの画面の遷移についてどうなっているかというと
<input id="game-start" type="checkbox"> <input id="reset" type="reset"> <label class="stage stage--op" for="game-start">スタート</label> <div class="stage stage--main">....</div> <label class="stage stage--end" for="reset">...</label>
.stage { position: absolute; display: block; width: 100vw; height: 100vh; } .stage--op { display: flex; align-items: center; justify-content: center; } .stage--main { display: none; } .stage--end { display: none; opacity: 0.3; background: black; color: white; font-size: 36px; } #game-start:checked ~ .stage--op { display: none; } #game-start:checked ~ .stage--main { display: block; } #game-start:checked ~ .stage--end { display: flex; align-items: center; justify-content: center; flex-direction: column; animation: game-end-animation 30s; } @keyframes game-end-animation { 0% { visibility: hidden; z-index: -1; } 99% { visibility: hidden; z-index: -1; } 100% { visibility: visible; z-index: 100; } }
こうなっている。
「スタート」は的と同様の作りになっています。
チェックが入ったらゲームの画面が表示されます。
同時に「おわり」の画面も"表示"されますが、visibility
を使い非表示にしています。
またz-index
を下げてゲームの画面に覆いかぶさらないようにします。
30秒立つと「おわり」の画面をanimation
で、z-index
が100になり、またvisibility
で表示するようにします。
「おわり」の画面は的と同様にlabel
となっていて、for
は<input type="reset">
に向けます。
reset
は、クリックするとform
要素内のinput
を初期値に戻します。
これによりスコアはリセットされ、また「スタート」の画面が表示されるようになっています!
まとめ
つかれた。。。
なんだかcounter
とかpointer-events
とかさ、お前らまじでCSSなの?大丈夫?みたいなこと思ったりしたけど、まぁ便利なのでいいんじゃないかな〜(ハナホジ
とりあえず、これぐらいのことは結構普通にできるんやで〜CSSすごいな〜って思いました。
みんなもHTMLとCSSだけで面白いものつくっていこうな!!!!