今回はThree.jsでPOLAR STAR(ポーラースター)のようなゲームを作ります。

POLAR STARは1983年発売の疑似3Dシューティングゲームです。敵は後方画面外からも撃ってきます。レーダーがあり、画面外の敵の位置が表示されます。要塞を攻撃するためには連射できない特別な弾が必要で、これを撃つためにはエネルギーのチャージが必要。しかもそのあいだは一方的に敵の攻撃を受け続け、一切の反撃ができません。敵機の攻撃をよけながら要塞攻撃のチャンスを狙うという忍耐力が必要なゲームです。

ちなみにこれが本物のポーラースターの画面です。

HTML部分

HTML部分を示します。

index.html

style.css

グローバル変数と定数

グローバル変数と定数を示します。

index.js

isPlaying と isGameovered の変数があります。プレイ中でないならゲームオーバーの状態ではないのか?ひとつにまとめられるのではないのかと思うかもしれませんが、ゲームオーバーになってもしばらく更新処理をおこなわないといけないので2変数にわけています。

マテリアルを生成する

敵と弾丸、火花の3Dオブジェクトを生成するときに必要なマテリアルを生成し、グローバル変数に保存する処理を示します。

自機やボス敵は平板に描画(後述)しますが、ザコ敵と弾丸はスプライトを使用して描画します。

Playerクラスの定義

自機を操作できるようにPlayerクラスを定義します。

コンストラクタ

自機はつねにひとつしかないのでアプリケーションが開始されたらすぐに生成し、それを使い回すことにします。自機死亡時は一時的に見えない場所に移動させることにします。

自機は平板を生成してその上にテクスチャを貼り付けます。敵や弾丸はつねに正面を向いた状態で描画したいのでスプライトを使用しますが、自機はやや水平に傾いた感じで描画したいのでこの方法を取ることにします。

座標はレーダーに描画するときの座標です。3Dオブジェクトの座標はX座標は同じですが、Y座標は基本的に0であり、Z座標はPlayer.Yとなります。また生成した3Dオブジェクトはすぐにsceneに追加します。

初期位置に戻す

自機死亡時に初期位置に戻す処理を示します。

移動

自機を移動させる処理を示します。

移動可能範囲内であれば押下されたボタンの方向に移動させています。また3DオブジェクトのY座標を生存時は 0、死亡時は見えない座標(-10000 とか)に設定しています。

描画

自機をレーダーに描画する処理を示します。生存時に小さな正方形で描画させています。

弾丸の発射

弾丸を発射する処理を示します。

このままだとキーを押しっぱなしにしているときは弾丸が連射され、線上につながってしまうので、連射は0.2秒以上開けないとできないようにしています。

charging == false のときは自機が敵要塞のコアを破壊できる距離まで接近してできていないときなので連射可能です。charging == true のときは敵要塞のコアを破壊できる距離まで接近しているときなのでエネルギーチャージが完了しているときのみ発射処理をおこないます。

またスマホだとこういうゲームはやりにくいので発射ボタンを押しっぱなしにしているときは連射できるようにしています。

PlayerBulletクラスの定義

自機から発射された弾丸を操作できるようにPlayerBulletクラスを定義します。

コンストラクタ

コンストラクタを示します。コンストラクタの引数はレーダーに描画されるときの座標であり、3Dオブジェクトの座標ではありません(Y座標とZ座標が入れ替わる)。グローバル変数に格納されているマテリアルをつかってスプライトを生成し、sceneに追加します。

移動

弾丸を移動させる処理を示します。

向こうまで飛んでいった弾丸は地平線の向こう側に落下していきます。これを表現するためにレーダー上のY座標(3DオブジェクトのZ座標)が0になったら落下フラグをセットします。1更新あたり高度を 0.5 ずつ下げ、-10 まで下がったら死亡フラグをセットしてsceneから取り除きます。

Enemyクラスの定義

敵を操作するためにEnemyクラスを定義します。

コンストラクタ

コンストラクタを示します。

敵はレーダーの一番上または一番下に出現します。そして回転をしながら下または上に移動します。一度上下のレーダーの範囲外に出たらそのオブジェクトは消えてしまいます。そして自機からみて向こう側から出現する敵は地平線の向こうから上がってくるような演出を加えます。

移動

上昇中の敵は上昇させ、降下中の敵は降下させます。地平線の向こうに消えた敵は死亡フラグをセットしてsceneから取り除きます。

上昇中でも降下中でもない敵は回転運動をさせるとともに向かってくるか後ろから迫ってくるかに応じで回転の中心座標を変更します。

レーダーの上側から外へ出た敵は降下フラグをセットして下側から外へ出た敵は死亡フラグをセットしてsceneから取り除きます。

描画

レーダー上に描画する処理を示します。

EnemyBulletクラスの定義

敵弾を操作するためにEnemyBulletクラスを定義します。やることはPlayerBulletクラスと似ていますが、進行速度、弾丸の進行方向が上下存在すること、視認性を考慮して弾丸の大きさを変えながら進行する部分が異なります。

コンストラクタ

コンストラクタを示します。メンバ変数として IsMoveDown と UpdateCount が増えました。

移動

向こう側へ向かって移動する弾丸の処理はPlayerBulletクラスとほぼ同じです。また更新回数に応じで弾丸の描画サイズを大きくしたり小さくしたりします(描画のみで当たり判定は変更しない)。

Sparkクラスの定義

爆発にともなって生じた火花を操作するためにSparkクラスを定義します。

コンストラクタ

コンストラクタの引数は火花の発生場所の座標と移動速度とタイプです。火花はレーダーには描画しないのでコンストラクタの引数の x, y, z は3DオブジェクトのXYZ座標です。

ザコ敵を倒したとき、敵要塞を破壊したとき、自機が破壊されたときで火花のタイプを変えます。ザコ敵を倒したときと比べて自機が破壊されたときは大きな爆発にします(テクスチャの切り替えを遅くすることで長時間表示されつづけるようにする)。また敵要塞が爆発するときは遠い場所なので火花自体を大きめのサイズにします。

爆発は同じテクスチャを使用するのではなく更新回数で別のものを使います。

なのでコンストラクタ内で一気に複数のスプライトを生成してMove関数内で入れ替え処理をおこないます。

移動

火花を移動させる処理を示します。更新回数によって使用するスプライトを変更します。コンストラクタ内で用意したすべてのスプライトを使い切ったらその火花は死亡フラグをセットしてsceneから取り除きます。

Bossクラスの定義

敵要塞を操作するためにBossクラスを定義します。

コンストラクタ

敵要塞は最初は地平線の向こうに隠れていて、自機が進行すると地平線の向こうから顔をだします。そこで地平線の向こう側にある敵要塞の下側が見えないように背景色(黒)と同じ色の板で隠します。

敵要塞にはコアがあります。この部分は自機が射撃可能な距離まで接近するまでは見えないように見えない位置にセットします。

初期化

Init関数は要塞の初期のY座標(3DオブジェクトのY座標)を設定します。ステージ数 + 1 に -50 を掛け合わせた値を設定します。

移動

要塞を地平線の向こうから徐々に現れてくるようにY座標を増やす処理を示します。要塞のY座標が +10 に満たないときは自機が要塞のコアを射撃可能な位置まで接近できていないのでコアは見えない位置に配置します(3DオブジェクトのY座標を -10000 のような極端に小さい値にする)。射撃可能な場合は -10(要塞本体の中心よりも少し下)に配置します。そして更新処理がおこなわれるたびに左右に移動させます。

自機が敵弾に当たってしまった場合は要塞から少し遠ざかった場所から再スタートとなります。KeepAway関数はそのときのために要塞を遠ざける処理をおこないます。

爆発の処理

要塞を爆発させる処理を示します。

要塞を爆発させるときは爆発の発生 × 2、要塞の消滅、爆発の発生の処理をおこないまs

座標の取得

要塞本体とコアのX座標またはY座標を取得する関数を示します。この関数は外部から要塞本体とコアの座標を取得したいときに呼び出します。

長くなってしまった(汗)。続きは次回とします。