こんにちは!最近開発部に入った橋本です。
弊社の開発部に入ると行う研修の 1 つに「JavaScript を使った何かを作る」というものがあるのですが、僕は React を使ってテトリスを作ったので紹介したいと思います。
目次はこちら
- 1. React を使って作成したテトリス
- 2. テトリスを作る際に使用した技術
- 3. ソースコードの解説
- 4. まとめ
React を使って作成したテトリス
こちらで実際に遊ぶことが出来ます。
(画面右上の音声アイコンを押すと BGM や効果音が流れます)
だいたいテトリスらしいものが出来たのではないかと思っています。
ソースコードはこちらから確認出来ますので、細かい実装部分まで見たい方はどうぞ。
テトリスを作る際に使用した技術
– React
– TypeScript
– Chakra UI
JavaScript さえ使っていればどんな技術を使っても OK という自由な研修だったので、弊社の開発でも採用されている React と TypeScript、そしてスタイルには個人的に使ってみたかった Chakra UI を使いました。
また React 16.8 で追加された Hooks も積極的に使って実装しました。
画面描画はよく使われる canvas は使わずに、React の state 更新だけで作ってみました。
ソースコードの解説
細かいところはソースコードを見てもらうとして、ゲームについてざっくりと解説します。
画面構成
4 つの画面を作りました。
画面 | 説明 |
---|---|
イントロ | 最初に表示される画面。Start ボタン押下でカウントダウン画面へ切り替え |
カウントダウン | カウントダウンして 0 以下になったらステージ画面へ切り替え |
ステージ | ゲーム本体の画面。ゲームオーバーでリザルト画面へ切り替え |
リザルト | スコアを表示する画面。Retry ボタン押下でカウントダウン画面へ切り替え |
画面の切り替えは scene という state を作成して行っています。
{scene === "intro" ? ( <Intro onClickStart={() => setScene("countDown")} /> ) : scene === "countDown" ? ( <CountDown onCountOvered={() => setScene("stage")} isSoundOn={isSoundOn} /> ) : scene === "stage" ? ( <Stage onGameOvered={handleGameOvered} isSoundOn={isSoundOn} /> ) : ( scene === "result" && ( <Result score={score} onClickRetry={() => setScene("countDown")} /> ) )}
ゲーム本体部分の処理の流れ
ステージ画面に遷移すると、自動的にテトリスが始まります。
1. ターン開始
2. キーボード操作で落ちブロックを下左右に移動または回転。一定時間ごとに落下
3. 落ちブロックが下まで落ちきる
4. ゲームオーバーの判定(ゲームオーバーの場合、リザルト画面へ遷移)
5. 落ちブロックを反映した盤面を準備
6. 消える行の判定
7. 消えた行の数に応じて成績更新
8. 行を消したあとの盤面を準備
9. 次の落ちブロックを準備
10. 盤面、落ちブロック、次の落ちブロックを更新
11. 次のターン開始
上記の一連の処理を 1 ターンとして、turnState というオブジェクトの state を作って複数の状態を管理しながらターン進行を行っています。
下記が turnState を初期化している部分になります。
const [turnState, setTurnState] = useState({ field: [...Array(FIELD_SIZE.rows * FIELD_SIZE.columns)], dropBlock: createBlock(), nextDropBlock: createBlock(), isDropped: false, });
それぞれどういう情報を管理しているかは下記の通りです。
キー | 説明 |
---|---|
field | 盤面の情報(どの座標に何色のブロックがあるか)を格納 落ちブロックは落ちきったあとにここに反映される |
dropBlock | 現在の落ちブロックの情報を格納するオブジェクト – 落ちブロックのサイズ(全て 4 x 4 ですが一応) – 左上の座標(移動すると変わる) – どの座標に何色のブロックがあるか(回転すると変わる) |
nextDropBlock | 次の落ちブロックの情報を格納(格納する情報の種類は dropBlock と同じ) |
isDropped | 落ちブロックが落ちきったかどうかのフラグ。これを切り替えることでターン開始と終了の処理を行う |
これらの状態を都度更新していくことでゲームが動いています。
まとめ
以上、「会社の研修で React 使ってテトリス作ってみた」でした!
React でゲームを作ったのは初めてだったので描画タイミングを考慮する必要があったりして苦戦しましたが、なんとなく使っていた Hooks についても改めて調べたりして良い勉強になったと思います。
また Chakra UI を使ったスタイリングも慣れてくるとサクサク書いていけるので、別の機会にも使っていきたいと思いました。
皆さんもよかったら React でゲームを作ってみてください!