弾幕幾何

附録Dは、弾幕シューティングゲーム(以下「弾幕STG」と略記)における「弾幕」の種類や特性の分類を独自の視点からまとめあげた文書です。

  1. データとしての弾幕幾何
  2. 弾幕幾何の分類
  3. 弾幕幾何のオブジェクト指向的実装

本節(1節)では、データの集合としての弾幕のオブジェクティブな捉え方を考察します。

「弾幕」という言葉に明確な定義はありません。敢えて説明するとすれば、弾幕とは「一定の規則性を持って時間発展する弾の群」となるでしょう。

これでは分からないので、具体的に弾幕を構成している要素について考察します。

ユニット

弾幕は何もない所から発生するわけではありません。弾を発射する敵や自機というユニットがまず必要になります。弾幕 STG をする上では考えなければなりませんが、弾幕幾何を構成するだけならば、あまり重要な要素ではありません。

弾と弾幕群

進行方向が違う
赤の弾幕群は左へ、青の弾幕群は右へ進んでいる
偶数弾と奇数弾
赤の偶数個の弾は並進しても当たらないが、青の奇数個の弾は中央が直進して当たる。

当然ですが、弾幕は弾の集合です。しかし、弾幕を考える上で全ての弾を一括りにしてしまうのは不都合です。なぜなら、種類の違う弾が複数あったり、同じ種類でも移動が左回り・右回りであったり、偶数弾と奇数弾[*1]があったりするからです。

そこで、弾幕を真っ平らな弾の集まりと捉えるのではなく、弾幕群の集合と捉える事にします。ここでは、弾幕群は次のように定義します。

  1. 弾は弾幕群である
  2. 弾幕群の集合は弾幕群である

このように、弾幕群の弾幕群を考えることで、複数の弾幕群が規則的に発展する場合など、より複雑な表現に対応することができます。この定義で、弾幕群は木構造的になっているので、根の側の弾幕群を上位の弾幕群、葉の方の弾幕群を下位の弾幕群と呼ぶことにします。

但し、弾も弾幕群として定義しましたが、以降混乱がないように単独の弾は「弾」、複数の弾の集合は「弾幕群」と表記して説明します。

弾幕群の時間

弾幕は時間変化するので、当然時間という概念も必要です。ここで重要なのは、弾幕とユニット、世界全体で共有の時間を持つのではなく、個々の弾幕群が個々に時間を持つということです。

例えば、弾幕群 C があるとします。弾幕群 C の時間 T_C は、 C が作られた時を 0 とします。 C が含む弾 b_1, b_2 , … は、 C が作られるのと同時( T_C = 0 )に発射されるかもしれないし、 1秒ごとに追加発射されるかもしれないので、個々の弾の時間 t_1, t_2, … は同じとは限りません。さらにその後の個々の弾 b_i の軌道は、弾幕群 C で共有される時間 T_C の時間にもよるし、個々の弾の時間 t_i にもよるでしょう。

このように、時間の要素は、ユニット・弾幕群・弾の全てについて個々にあるべきです。個々に時間の要素を与えることで、共有時間一つのときよりも簡潔かつ豊かに表現することができます。

位置と速度

そして当然ですが、弾一発一発について位置と速度という情報が必要です。まず当然位置は必要です。では速度はどうかと言うと、これもあった方が便利です。というのは、弾幕群の弾を効率良く統制するためには弾の「向き」が重要だからです。しかし、加速度はほぼ必要ありません。なぜならば、大抵の弾幕は規則変化(等速運動を含む)を行うからです。限られた規則変化を記述するのには、速度を時間の関数で与えれば事足ります。加速度で速度を時間発展させ、さらにその速度で位置を時間発展させる、というモデルを取るのは流石に大げさです。

弾幕群の移動
個々の弾が移動しているのではなく、弾幕群の中で規則正しく移動しつつ弾幕群全体として移動する。

逆に、「速さ」は純粋に難易度のパラメータなので、弾幕幾何を考える上ではさして重要ではありません。では向きの情報だけでいいのかというとそうでもなくて、弾ごとに速さの差をつけたい場合などがあって、やはり速度が便利なのです。ただここで重要なのは、弾幕群同士の相対速度です。

位置と速度も、ユニット・弾幕群・弾の全てが個々に持つべきです。

例えばサイクロイド型に移動する弾の位置は、時間をパラメータとする媒介変数表示で記述するよりも、等速度運動する弾幕群を基準(中心点)として円運動させるべきです。

描画属性

また、弾幕群は何らかの描画属性を持つ必要があります。例えば、弾の色や大きさなどの視覚的な情報です。これが異なるだけで全く違う弾幕になるので、非常に重要な要素です。

もし個々の弾ごとに描画属性を設定すると、実装過程で無駄が多く、綺麗な弾幕を実装することが難しくなります。基本的に、上位の弾幕群に対して描画属性を一つ設定し、下位の弾幕群には同じ描画属性を適用するのがいいでしょう。

こうして描画属性の継承パターンが決定したら、描画する時は継承元から再帰的に描画を適用するだけです。

まとめ

データ構造のまとめです。

  • ユニット [時間] [位置] [速度] [属性]
    • 弾幕 [時間] [位置] [速度] [属性]
      • 弾幕群 [時間] [位置] [速度] [属性]
      • 弾幕群 [時間] [位置] [速度] [属性]
          • 弾 [時間] [位置] [速度] [属性]
          • 弾 [時間] [位置] [速度] [属性]

弾幕を実装する上で最も基本的なデータ構造を考察してきましたが、さらに細かく弾幕を実装するためには他の要素(パラメータ)が必要になる場合もあるでしょう。

しかし、あまり不要なパラメータを導入すると弾幕の依存関係や構成が分かりにくくなってしまうので、可能な限り、今まで挙げた基本要素を中心に構成するべきです。特に、オーバーヘッド(計算による処理時間のロス)が生じないように、下位の弾幕群の実装には気をつけるべきです。

注釈

*1
偶数弾と奇数弾の図から分かるように、偶数個の弾は安全で、奇数個の弾は危険です。そのため、避けなくても安全な自機狙いではない弾のことを"偶数弾"と呼びます。対して、避けなければ当たる自機狙いの弾のことを"奇数弾"と呼びます。