オブジェクトが動く仕組み

● オブジェクトの移動とは ●

 - SHIORI - では、『オブジェクト特性』で定義された「振る舞い」の情報に従って、『オブジェクト』が動き回るということを、前章で述べました。
 ここではその「振る舞い」について、どういった仕組みで『オブジェクト』の動きを取り扱うのか、少し詳しく解説します。

オブジェクトの移動とは?

 『オブジェクト』が画面上を動くということは、要するに、連続的に座標が変化するということです。
 X座標が連続的に大きくなっていけば、『オブジェクト』は右方向に進んでいきますし、Y方向に連続的に大きくなっていけば、下に進んでいきます。
 したがって、『オブジェクト』の移動パターンを定義するということは、座標の変化を連続的に定義することにほかなりません。

 - SHIORI - のオブジェクトは、座標を管理するために、以下のパラメータをもっています。

 座標値は、『オブジェクト』が現在どの場所にいるか。移動速度は、次のフレームにどのくらい座標値が変化するか。加速度は、次のフレームにどのくらい移動速度が変化するかを表しています。

 2次元の座標系で管理している『オブジェクト』があったとして、そのパラメータが

だったとき、次のフレームでの『オブジェクト』の状態は、以下のようになります。

 通常は、速度や加速度を使って、オブジェクトの動きを定義すれば十分でしょう。
 『オブジェクト』の初期位置を設定するとき、もしくは瞬間移動するような場合のみ、直接座標に値を設定することになると思います。

 具体的な例を、下に2つほど紹介します。

例)放物線運動

 高校物理の、ごく初期に出てくる問題ですが、、、
 たとえば、野球のボールを遠投する場合にボールが描く軌跡を表したい場合。

 この状態を維持して - SHIORI - に演算させていけば、ボールを投げたような動きが実現できます。
 最初は右上方向の速度をもっているのだけれども、加速度により徐々にY方向の速度が落ちていって、最後には下方向に落ちていくようになります。


放物線運動
(x,y,Vx,Vy,gは、それぞれ正の値。tはフレームカウント)

例)ファミコン版『グラディウス』の最初に出てくる敵みたいなものの場合。

 ファミコン版『グラディウス』の最初に出てくる敵は、まず画面の右上に登場して、しばらく左方向に移動していきます。 ある地点まできたら、右下に移動しはじめ、最後は水平に右方向に移動していきます。
 これを実現したい場合は、、、

こんな感じで、速度を制御していきます。


ファミコン版『グラディウス』の最初の敵っぽいもの

動きを定義する方法

 動きを定義するには、ふたつの方法があります。

  1. 配列を使用する方法
  2. コマンドセットで値を制御する方法

 配列を使用する方法を使うと、比較的簡単な動きを、簡単に記述することができます。ザコキャラの定義をするときなどに使用すると良いでしょう。
 コマンドセットで制御する方法を使うと、より細かい制御を行うことができます。 ボスキャラなどの複雑な動きをするものの定義をするときに使用します。

 ここでは、配列を使った定義方法について解説します。
 コマンドセットについては別の項で解説します。

● 配列による移動パターン定義 ●

配列によって動きを定義するときに必要な概念

 配列を使用して動きを定義するときには、以下のような概念を使用します。

 基本的に、動きは『配列』で定義します。
 『配列』は『ベクタ』を並べたものです。
 『ベクタ』は、いくつかの「値」を組み合わせたものです。 
 『配列ポインタ』は、『オブジェクト』が現在配列上で、どの位置を処理しているかを表します。

 それぞれの詳細を以下で解説します。

座標系について

 上の例で述べたように、『オブジェクト』の位置は座標値で管理します。 2次元座標系であれば、X座標とY座標の2つの値で、『オブジェクト』の座標が表現されることになります。 2Dのシューティングゲームを作るのであれば、通常は2次元の座標系を取り扱えれば問題ないでしょう。

 ここで、ひとつ重要な注意点があります。
 - SHIORI - では、『オブジェクト』が管理する座標系を規定していません。 - SHIORI - が取り扱う座標系は、常に2次元のX-Y座標系であるとは限らない、ということです。

 何故、次数を2次元と規定していないのか。
 たとえば『メタルブラック』みたいなゲームなら、X-Yの2次元座標系を取り扱えれば問題ありません。 しかし、『レイフォース』みたいなゲームだったら、どうでしょうか。 一応2Dのシューティングゲームではありますが、登場するキャラクタ自体は、奥行きを持った動きをしています。 この場合、座標系は X-Y-Z の3次元の座標値を取り扱えないといけないことになります。
 では、『レイストーム』はどうでしょうか。 『レイフォース』と同様3Dでキャラクタが動きますが、こんどはポリゴンになっています。 ポリゴンモデルのオブジェクトを取り扱う場合は、X-Y-Z の座標とともに、回転成分 Rx-Ry-Rz を管理する必要も出てきます。 この場合、キャラクタが取り扱うべき座標系は X-Y-Z-Rx-Ry-Rz の6次元座標系になります。

 このように、作ろうとしているゲームによって、『オブジェクト』が取り扱うべき座標系の次数も変わってきます。
 - SHIORI - は汎用のシステムを目指していますので、これに対応するため、『オブジェクト』にとっての座標系を自由に設定できるようになっています。

ベクタについて

 1個以上の「値」を組み合わせたものを、『ベクタ』もしくは『ベクトル』と呼びます。 どちらの呼び方も元は英語で "Vector" であって、同じ単語です。
 具体的には、「(10 , 10)」とか「(-32 , 64 , 80)」なんてものが『ベクタ』です。

 『オブジェクト』の座標値や速度,加速度は、全て『ベクタ』で管理します。
 『ベクタ』は複数の「値」を組み合わせたものですが、いくつの値を組み合わせるかは自由に決められます。 2次元の座標「値」を取り扱いのであれば2つの「値」を組み合わせたベクタを使えば良いし、3次元の座標値を取り扱いたいのであれば、3つの「値」を取り扱えるベクタを使えば良いでしょう。

 ベクタが取り扱う「値」は、普通は何らかの数値ですが、必ずしも数値だけとは限りません。 場合によっては文字列を「値」として使用することもあります。

 ベクタは、「(a,b,c)」のように、「( )」で囲って、「 , 」で値を区切って表現します。
 2次元座標系なら「(320,240)」、3次元座標なら「(320,240,100)」みたいな感じで表現します。

配列について

 配列とは、『ベクタ』を並べたものです。

 『オブジェクト』の動きは、この『配列』を使用して定義します。

 上で述べたように、『オブジェクト』の移動を定義するということは、座標の連続的な変化を定義するということです。
 『オブジェクト』の座標は『ベクタ』を用いて表現します。 その『ベクタ』を連続して並べることにより、『オブジェクト』の座標の変化を連続的に定義できます。

 移動を定義するための配列では、(『オブジェクト』が取り扱う『ベクタ』の次数+1)の次数をもった『ベクタ』を使用します。
 つまり、2次元座標系で座標が管理される『オブジェクト』では、『配列』の要素として3次元の『ベクタ』を使用します。
 3次元座標系で座標が管理される『オブジェクト』では、『配列』の要素として4次元の『ベクタ』を使用します。
 『オブジェクト』が必要としている次数に対して、余分なひとつの次数は「繰り返し回数」をあらわします。

 たとえば、2次元座標系の『オブジェクト』の動きを定義するための『配列』では、具体的に以下のような定義をします。

(-40,0 , 3) , (40,40 , 3) , (40,0 , 3)

 これは、(-40,0) が3個、(40,40)が3個、(40,0)が3個ということを意味しており、- SHIORI - 内部では

(-40,0) , (-40,0) , (-40,0) , (40,40) , (40,40) , (40,40) , (40,0) , (40,0) , (40,0)

と解釈されます。

 『オブジェクト特性』に上記のような『配列』を、『速度ベクタの配列』として定義すると、「最初の3フレームは左方向に、次の3フレームは右下方向に、最後の3フレームは右方向に動く」ということを定義したことになります。

配列ポインタについて

 プログラムを少し知っている人は、『配列ポインタ』=配列の添え字、と考えてもらえれば間違いありません。 Cを知っている人は、配列上の要素を指すポインタ、と思ってください。 その認識で、ほぼ正確です。

 『オブジェクト』の動き方を定義する配列は、『オブジェクト特性』に定義します。 上で解説した『配列』も『オブジェクト特性』の一部として定義します。

 『オブジェクト特性』に定義するのは、『オブジェクト』が動く軌跡のみです。 要するに、『オブジェクト』が通る通り道を用意するだけです。
 『オブジェクト』はその通り道の上を通るわけですが、実際に『オブジェクト』が移動するときには、『オブジェクト』自身が現在通り道上のどの位置にいるのか、という情報が必要です。 要するに、現在位置ですね。

 『配列ポインタ』は、その「通り道上のどの位置にいるか」ということを取り扱うためのものです。
 『オブジェクト』はそれぞれ『配列ポインタ』を持っています。 『オブジェクト』は、『配列ポインタ』が指し示す位置を参照して、その位置にある『ベクタ』を取り出し、取り出した『ベクタ』の内容に従って次の移動先を決定します。


配列ポインタと軌跡の関係

 たとえば、上のような軌跡を定義した配列があったとします。
 『オブジェクト』は、それぞれ『配列ポインタ』を持っているわけですが、@,A,Bがその配列ポインタだったとします。
 @の位置を指し示す『配列ポインタ』を持っている『オブジェクト』は、次のフレームでは、少し左方向に移動します。
 Aの位置を指し示す『配列ポインタ』を持っている『オブジェクト』は、次のフレームでは、少し右下方向に移動します。
 Bの位置を指し示す『配列ポインタ』を持っている『オブジェクト』は、次のフレームでは、少し右方向に移動します。

 配列ポインタは、1フレームごとに、自動的に先に進んでいきます。 配列ポインタは、通常、最初は先頭の要素を指していますが、1フレームの移動が済むと、自動的に次の要素を指すように移動します。 ですから、通常は配列ポインタ自体の動きを直接制御する必要はありません。

 逆に、いくら『配列』を定義しても、『オブジェクト』が『配列ポインタ』をもっていなければ『オブジェクト』に動きを与えることができません。 『オブジェクト』が『オブジェクト配列』を参照するための手段が無くなってしまうからです。 『配列ポインタ』は、『オブジェクト』に『配列』を関連づけるためのブリッジなのです。

● まとめ ●

まとめ

 オブジェクトを移動させるための、おおまかな手順は以下のとおりです。

  1. 『オブジェクト』が取り扱う次数を決定する。
  2. 『オブジェクト特性』に『ベクタ』を並べた『配列』を定義し、『オブジェクト』の通り道を定義する。
  3. 『オブジェクト』に『配列ポインタ』を持たせ、『オブジェクト』と『配列』の関連づけを行う。

戻る