入社して早くも2か月が経ちました。5月に入ってからはOJTとはいいつつも本格的に開発が始まり、私はフロントエンドの担当ということで初めてreactを使うことになりました。しかしながらhtmlもcssもjavascriptも触ったことがなかったので(そもそも開発経験なし)現在進行形で苦しみながら開発を進めております。せっかく苦しみながらも少しづつ使えるようになってきたので、TechBlogのネタ作りも兼ねて何か作ってみようと思っていたところ、先日たまたま友人とスロットを打ちに行ったことを思い出しました。スロットでは目押しと呼ばれる技術が必要となってくるのですが、初心者であるためかなかなかうまくできなくて少々損をしてしまっていたように感じます。そこで、自分で疑似的なスロットマシンを作れば無料で目押しの練習ができるのではないか(ホント?)という軽い思い付きが生じ、今回はスロットマシンを作ることに決めました。
目標
目標を確認しましょう。このスロットマシンは3つのリールと3つのボタンから成っています。それぞれ1つずつ作ったらあとはほとんどコピペです。
それではSlotMachine.jsとSlotMachine.cssというファイルを作り、前者に機能面のコード、後者にスタイルを書き込んでいきます。
リールを作る
まず初めに下図のようなリールとして使う画像をペイントやパワポなどで適当に作り、SlotMachine.jsと同じ階層に置いておきます。
画像を作ったらSlotMachine.jsにインポートしてリールを作っていきます。ここで、リールが無限に回転しているように見せるアニメーションをつけるために、同じ画像を二つ読み込むというのがポイントです。
import React from "react";
import reel from "./reelSample.png";
import "./SlotMachine.css";
function SlotMachine() {
return (
<div className="reel">
<img id="left1" src={reel}></img> //リールの画像
<img id="left2" src={reel}></img> //リールの画像
</div>
);
}
次にSlotMachine.cssでリールのスタイルを決めていきます。.reel img:first/last-childの中で起こすアニメーションと時間を指定し、そのあと@keyframsで指定したアニメーションの詳細を記述します。@keyframs loop/loop2の中ではアニメーション開始時と終了時のオブジェクトの位置を指定します。ここではリールをY軸方向に動かしたいのでtransitionY()を使って指定します。
/*リールの枠のスタイル*/
.reel {
position: relative;
display: flex;
flex-direction: column;
height: 277px; //適宜調整
width: 200px; //適宜調整
border: 1px solid black;
overflow: hidden; /*枠から飛び出た部分は見えないようにする*/
box-shadow: 0px 70px 35px -20px rgba(0, 0, 0, 0.4) inset, /*上に影を付ける*/
0px -70px 35px -20px rgba(0, 0, 0, 0.4) inset; /*下に影を付ける*/
}
/*リール内の画像のスタイル*/
.reel img {
position: relative;
z-index: -1; //画像が影の下に来るようにする
height: auto;
width: 200px;
}
/*1枚目の画像のアニメーション*/
.reel img:first-child {
animation: loop 4s -2s linear infinite; /*アニメーション*/
animation-direction: reverse; /*アニメーションの方向を逆にする*/
}
/*2枚目の画像のアニメーション*/
.reel img:last-child {
animation: loop2 4s linear infinite;
animation-direction: reverse;
}
/*1枚目のアニメーションの詳細*/
@keyframes loop {
0% {
transform: translateY(100%);
}
to {
transform: translateY(-100%);
}
}
/*2枚目のアニメーションの詳細*/
@keyframes loop2 {
0% {
transform: translateY(0%);
}
to {
transform: translateY(-200%);
}
}
ボタンを作る
SlotMachine()のreturnの中にボタンを作り、CSSも編集します。
<input type="button" id="buttonLeft"></input>
#buttonLeft,
{
width: 40px;
height: 40px;
background-color: blue;
border: 1px solid black;
border-radius: 20px;
}
ボタンのクリックでアニメーションを止める
ここまででリールのアニメーションはできましたが、ボタンを押したときに止まってくれないと意味がありません。したがって、ここではボタンのonClickを使ってアニメーションを止められるようにします。アニメが起動しているか否かの状態はstyleの中のanimation-play-stateプロパティの中に格納されており、動いているならばrunning、止まっているならばpausedとなります。ここでやりたいのはボタンのクリックをきっかけにこの状態を切り替えることです。
SlotMachine関数の中でpauseLeft()という関数を定義します。この関数はdocument.getElementById()によってアニメーションを含む要素を取り出し、その要素のanimation-play-stateプロパティの状態をif文を使って切り替えます。(ついでにボタンの色も変わるようにしました。)この関数を先ほど作ったボタンのonClickに入れればクリック時に呼び出されるようになります。
function pauseLeft() {
let left1 = document.getElementById("left1");
let left2 = document.getElementById("left2");
let buttonLeft = document.getElementById("buttonLeft");
if (left1.style.animationPlayState == "running") {
left1.style.animationPlayState = "paused";
left2.style.animationPlayState = "paused";
buttonLeft.style.backgroundColor = "red";
} else {
left1.style.animationPlayState = "running";
left2.style.animationPlayState = "running";
buttonLeft.style.backgroundColor = "blue";
}
}
<input type="button" id="buttonLeft" onClick={pauseLeft}></input>
これで1レーン分のリールができたので、同じ要領で残り2つも作れば完成です。
デモ
課題
デモを見てもらえばわかると思いますが、このスロットマシンでは枠内のどの位置であってもリールの回転を止めることができてしまいます。実物のスロットマシンではリール内の要素は必ず決まった位置で止まるのでその部分も是非再現したいところですが、この部分については次回に回したいと思います。
最後に
とりあえずそれっぽいものは作れました。なお、もっと簡単に作りたいという人はインターネットで検索すればreactのlibraryがいくつか出てくるのでそちらを使用することを検討してみてはいかがでしょうか。また、ここまで読んでくださった方はお気づきかもしれませんが、reactで作ったというタイトルでありながらreact特有の実装はほぼなく、cssとjavascriptの部分がほとんどでした。ただ、できたスロットマシンはコンポーネントとして使用できるので嘘はついてないと思います(汗)。
参考
無限ループするアニメーション部分 : 写真が画面の端から端へ流れる無限ループするアニメーション | chocolat | Freelance Frontend Engineer (chocolat5.com)
ボタンを押してアニメーションを止める部分 : animation-play-state 「アニメーションの一時停止/再開」【CSSリファレンス】 (cman.jp)