2019年01月10日
HTML5で作るはじめてのスマホゲーム【お正月編 投扇興】
こんにちは、コーディングファクトリー部の松原です。
私の主な業務は「案件・技術相談窓口」として、お客様からご相談いただいた案件の見積やスケジューリングをする上で必要な作業工数の算出を担当していますが、コーディングファクトリー部の元コーダーで、今でも休みの日には時々コーディングをしています。
今回は2019年1月のコーダーのあーだこーだの担当ということで、冬休みの自由研究も兼ね、HTML5で何かお正月らしいゲームを作ってみたい!と思いました。
そこでひらめいたのが「投扇興(とうせんきょう)」です。テレビや日本酒のイベントで何度か見たことがあったのですが、もしかすると初めて聞く方もいるかもしれません。
超簡単にルールを説明すると、数メートル先の台座(枕)にある的(蝶)に扇を投げて、蝶、枕、扇がつくる形(銘=投扇興の役)で得点を競うゲームです。百聞は一見に如かずということで、動画をご覧ください。
起源は江戸時代と言われていますが、今でもお座敷遊びとして人気です。また、競技として真剣に取り組んでいる方もいます。
ところでこの動き、何かに似てませんか?…そうです、スマホのフリックです!
スマホをフリックした時の状態を取得し、その結果で銘の判定をすれば、シンプルだけど投扇興の特徴を捉えたゲームができるのではないかと考えました。
タスクをイメージして、スケジュールを組む
ゲームを作るのは初めてなので、勝手はよくわかりませんが、必要そうな作業タスクを洗い出して、次のような感じでざっくり予定を立てました。
- 扇を投げる動き=フリックの状態をJavaScriptで取得する(1週目)
- ゲーム画面をコーディングし、画面遷移させる(2週目)
- 判定ルールの策定、判定結果を表示させる(3週目)
週末にそれぞれ4~5時間くらい使って作業するイメージです。
作業していくうちに、あれもこれもと追加要件が出てきそうですが、今回はゲームとしてまずかたちにすること第一目標とし、もっと見栄えをよくしたい、判定をこだわりたいなどのブラッシュアップは、今後の課題としています。
1週目:フリックの状態をJavaScriptで取得する
投扇興のスマホゲームを思いついたときは、単純にフリックの速度で結果を判定すればいいと考えていたのですが、HTML5ではスマホの傾きに関する値も簡単に取得できます。
「これも投扇興には不可欠な要素だろう(たぶん)」ということで、傾きについても判定材料とすることにしました。ちなみに私は投扇興を実際に体験したことはありません!なので、完全にイメージ先行ですが、前向きに考えると、型にはまらない新しいものが生まれそうな予感がしますね。
まずは、フリックの開始位置の座標(X,Y)をタッチイベントの「touchstart」で、終了位置の座標を「touchend」で取得し、ピタゴラスの定理で2点間の長さ(距離)を計算します。
今回の座標のように、イベントでどんな情報が取得できるのか、具体的な内容を知りたいときは、下記のようなコードを書いて、ブラウザのデベロッパーツールからConsoleを開いて確認しました。
次に、「new Date」で開始時刻と終了時刻を取得し、フリックに何秒かかったか(時間)を計算すれば、あとは距離÷時間=速度がわかります。
もう一つの判定材料「傾き」は、deviceorientationイベントで取得します。「方角(alpha)」「縦方向の傾き(beta)」「横の傾き(gamma)」がわかりますが、今回方角は関係ないので、betaとgammaのみ取得しました。deviceorientationは、PCだと角度が取得できずに「undefined」となってしまいますので、自分のスマホ(iPhone)を使って、アラートでそれぞれの値を表示して検証しました。
1週目はJavaScriptで値を取得するまでがタスクなので、ここまで。
2週目:ゲーム画面のコーディングと画面遷移
必要とするゲーム画面は、メインビジュアルとスタートボタンが表示されている「トップページ(1)」。スタートボタンを押すと表示される「ゲーム画面(2)」。ゲーム画面でフリックすると、「扇が飛んでいくアニメーション(3)」を挟んで、最後に「結果画面(4)」が表示される。という流れで、全4画面を想定していました。
今回、(1)~(3)で使用する画像は「いらすとや」のものを使用しました。それにしても、まさか投扇興の画像まであるとは!守備範囲が広すぎですね、いらすとや恐るべし。また、(4)の結果画面で表示する銘の写真はWikipediaのものを使用します。
まず、index.htmlに4つの<section>を記述し、CSSで「width: 100vw; height: 100vh;」に設定。フルスクリーンで表示されるこの4つの<section>の表示・非表示を、JavaScriptで切り替えてゲームを進めます。
要素自体は少ないのでコーディングは順調でしたが、使用するフォントで2時間以上悩むという落とし穴にハマってしまいました・・・。というのも、Google Fonts APIのページを見ていたら、面白いフォントエフェクトが沢山あったので、いろいろ試していたらあっという間に時間が過ぎていました。ちなみにエフェクトをかけると、なぜか(開発環境の問題かもしれませんが)iPhoneで表示されなくなってしまったので、今回は使用していません。フォントはイラストのイメージに合わせて「M PLUS Rounded 1c」というGoogleの日本語フォントを選びました。
というわけで、完全に時間配分を誤ってしまい、静的なコーディングが終わった時点で今週の目標タスクが達成できないのは確実です。そういうときは、ゲームに必要不可欠な機能の実装を優先し、オプション要素は省く!アニメーションの作成は一旦おいといて、画面遷移の実装を進めることにしました。
画面遷移の具体的な仕組みは、最初にJavaScriptでトップページの<section>以外を非表示としておき、ボタンのクリック(clickイベント)や、フリック後(touchendイベント)のタイミングで(1)〜(4)の順に遷移するように、表示非表示を切り替えていきます。
さらに、このゲームはスマホ専用なので、PCでアクセスした場合=deviceorientationが「undefined」の場合には、アラートを表示させるようにしました。
アニメーションは作れなかったけど、来週のタスクは予定どおり進められそうです。2週目はこの辺でタイムアップ。
3週目:判定ルールの策定、判定結果を表示させる
投扇興にはいくつか流派があるそうで、流派によって独自の銘定(役とその点数の定義)があります。今回ゲームで使用しているのは「日本投扇興連盟」の銘定。全31種類の銘には、それぞれ百人一首に因んだ名前が付けられています。3週目の作業は、JavaScriptでその銘の判定ルールを決めて、結果を表示させます。
まず、結果画面に表示される「写真(とalt)」「銘」「点数」「解説」は、動的に入れ替わる部分なので変数にして、JavaScriptで出力できるようにしておきます。この時点では、とりあえず表示確認が出来ればいいので、適当な値を出力しておきます。
次に、判定の関数を呼び出して、判定ルールにあわせて結果が表示されるように変更します。判定ルールは、フリックのそれぞれの数値(距離、幅、スピード、縦の傾き、横の傾き)が、ここからここまではこの銘、というように地道に if 文で分岐させました。これを31パターン設定するのは時間がかかりそうなので、ひとまず3パターンのみ作成しました。その判定の結果にあわせて表示される銘定リストには、2次元配列を使いました。
この時点でかなりコードが長くなってきたので、判定の関数と銘定リストを、それぞれjudgement.js、data.js のように、別ファイルに分けました。
この後はコツコツ31種類の判定ルールを考えて、if 文で分岐させれば完成です。
とはいえ、結果が3パターンだけでも、ゲームとして十分成り立っている気がしてきました。これってもう完成なんじゃないですかね?!そんな甘い気持ちで、3週目はここで終了。
ついに完成!のはずが・・・。
先週の時点で割と満足してしまったので、あとはのんびりパターンを増やしていこうかな、なんて考えていたら、ふとあることを思い出しました。「・・・あ、アニメーションやってないじゃん」。そうでした、すっかり忘れてました。(もうなくてもいいかなと思ったけど)そんなに時間がかかるものではないので、やります。
アニメーションはCSS3の transitionで、扇を手前から奥へ移動させながら、遠近感を出すためにサイズを小さくしていくだけです。画面遷移は、JavaScriptの「transitionend」を使って、アニメーションが終わったタイミングで切り替えます。
この一連の動きはすぐできましたが、ホームボタンでトップページに戻り、再度ゲームをスタートすると、なぜか2回目以降のアニメーションが表示されない(泣)。検証の結果、アニメーションの開始と画面切り替えの処理が同じタイミングで走っており、2回目以降はおそらくキャッシュのせいで、画面が切り替わる頃にはアニメーションが終了していたのでした(短いアニメーションなので)。再生タイミングを調整すると、無事2回目以降もアニメーションが表示されるようになりました。そうです、つまり・・・
完成しました!!!!
やったー、ありがとうございます。
完成したゲームはこんな感じです。
こちらのページにアクセスすると、実際にプレイすることができます。(スマホでアクセスしてみてください)
おわりに
ゲームを作ろうと思った当初は、かなりシンプルな仕様だし、大して時間はかからないだろうと思っていましたが、想像以上に細かい調整が必要だったり、今回はスマホのゲームだったこともあり、検証環境の準備(はじめはlocalhostをスマホで表示させたていたが、毎回設定が面倒だったり、Webフォントが読み込めない問題などがあり、最終的には GitHub Pages に移行)にも、そこそこ時間がかかりました。
また、31パターンの作り込みは、実はこれからで・・・この記事が公開される頃には何とか間に合わせたいと思っています。そもそもこのようなゲームを作るとき、if 文で分岐する以外に何かいい方法があるのかどうかも気になるところです。
今回はお正月編でしたが、また何か機会があればチャレンジしてみたいと思います。