Google

2014年1月20日月曜日

HTML5で3Dゲーム:Canvasで擬似3D

前回はCSS3Dに限界を感じ断念する話でした。
要は、この先の不安を考えれば2Dの方がはるかに安全という判断で、ここから大急ぎで3Dっぽいゲームを作ることになるのでした。
CSS3Dでのゲーム完成を期待されていた方は申し訳ございません。

なお、細かい判断理由は省きますが、幾つ買った候補のうち最終的に決まったのはenchant.jsでした。
当時は0.7.0になったばかりでしたが、CSS制御からCanvas制御になった事による高速化、日本語によるサポートやコミュニティの存在がなかなか大きかったと記憶しています。
欲を言えばPIXI.js位もう少しシンプルで高速だとさらに嬉しいですが、自分で作るしかない状況で無い物強請りは良く有りません。
逆に、当時日本語と文献や情報量で言えばこれしかなかったとも言えます。

という事で、再度これらの問題を2Dでどうにかする必要があります。
  • 接近する物体
  • 当たり判定
  • 床、壁
※1つ1つが長めの話になるので、今回は物体だけ解説です。

CSS3Dが使えないなら自前で3Dを表現するしかありません。
まず床と壁も含め、今回のゲームのような3Dの奥行きを2Dで表現するには「一点透視図法」という概念を使います。
簡単な図を以下に表示します。

拾い物の絵ですが、1点透視法ってざっとこういう事です。
点となって消える場所の消失点を軸にして物体の遠近を付ける方法で、絵描きさんなんかは良くご存知じゃないでしょうか。
この表示に関しては位置と焦点を元に画面上の位置を割り出す計算方法があります。


上図における焦点をZfとし、図の右上にあるP1の位置に存在する物体をスクリーン上で見る時のYsの位置は以下で割り出せます。

P2はP1よりも更に遠くにあるため、P1よりも下に小さく表示されるという事です。
しかし焦点の位置をゼロの中点と仮定すると、算出計算式がさらに簡単になったりするので、画面固定という条件をベースにそちらを使うことにしました。

先程のY計算だけでなく、X計算も簡易になります。
また、ペラペラの1枚板を接近させる想定なので、接近する物体の画像が持つx,y,width,heightは上記を元に算出できるという事になります。
問題は1つマスに何個最大障害物が存在するのか、というゲーム上の問題ですが、これは4個と決まりました。
最大で1マスに以下のように4つ並ぶ事になります。(田んぼの漢字じゃありませんw)

      □□
      □□

上の段を二段ジャンプで避けるという要求仕様もあったので、この程度で済む事になりました。
まあ、仕様が2列でも3段でも構造的に余り変化はありませんが。
今回の場合はそこそこ単純で、最小限でも4種類の画像(左上、左下、右上、右下)が1つのアイテムにつき必要となる訳です。
プロト作成実験で使うのはシンプルなこんな画像でした。

下段に来る物体のサンプル
こっちは上段。
ちなみにUnityで作成したBoxのキャプチャですw
そして先程の計算式を元に1フレーム毎に拡大し接近しているように見せかける訳です。
という事で今回公開するのはその際に作った第1弾のenchant.js版テストコードです。
画面は以下の様な感じ。

ひたすら接近する物体を眺めるだけの簡単なテストです。
上記デモを実際にブラウザで表示したい場合ははこちらからどうぞ。
ソースは拙いですがそのままご覧頂いて結構です。

ちなみに今回のデモで表示した物体接近は改良の余地が多々あります。
まず接近時の3D的な歪みがありません。
接近すれば視点移動で形状が変わるのですが、これは最終的に位置に応じた画像を差し替えることで対応しました。
先述の通り左右分の画像が無いですが、これも別途差し替えで対応できています。
前回触れたインスタンス管理やマップに関係する生成タイミング等も今回のデモでは出来ていませんが、これも最終版では全て使いまわし可能なように管理する形になりました。

また、この擬似接近の正体は、単にCanvas上で画像が拡大しているだけなので、物体の前後関係を管理してあげなければなりません。
このデモでは物体数が少ないため、あまり気にならないというだけの事です。

視点と画像の上下に関する当時の資料です。
こんな単純なこと考えてたことを思い出しました。

もし視点がぐりぐり変化するのなら全て計算しなければなりませんが、視点が固定であれば上図のように下段の物体が上段よりも上zのレイヤに来ることはありません。
また、各段の中では古いもの程zレイヤが上に来るため、その部分は単純です。
さらに影の有無はゲームに直結するため、これ以外にも影を描画する必要があります。上の影が下に被さってはまずいため、そこも物体の有無などを判断基準にして表示レイヤを管理する必要があります。

なお、enchant.jsが管理するimageはクラスにラップして管理を行う形になりました。
アイテム数が増えて結構大変にはなったのですが、とりあえずこれで物体はなんとかなったわけです。

次回は当たり判定と壁床の話です。

0 件のコメント:

コメントを投稿