シューティングゲームで学習した内容の応用例を確認してみよう

【さらに敵を登場させてみよう】
 更に,敵を登場させてみたのが以下のarray2.cppである。main.cppの中身と入れ替えて実行してみよ。
 薄緑色の2ヶ所(①と②)が新たに追加した部分である。

 ①では,敵機を表現するために必要な変数を用意している。まず,次の3つの変数が宣言されている。

変数名 意味   変数名 意味   変数名 意味
ex, ey 敵機の左肩の座標   eShip 敵機のグラフィック番号   eLife

敵機のライフ

 次に,3つの配列を使って,敵機の弾の状態,x座標,y座標を表している。

変数名 意味
int e_shots_Life[ 8 ] 8個の敵機の弾それぞれの未発射(0)・発射済み(1)かを格納する配列
int e_shots_x[ 8 ] 8個の敵機の弾それぞれのx座標
int e_shots_y[ 8 ] 8個の敵機の弾それぞれのy座標

 また,敵機に関しては8個同時に弾を発射するため,8個の弾が全て「未発射状態」状態にならないと
 弾が発射できない事情がある。そこで,『敵機が弾を発射できる状態』かどうかを管理する変数eShot_Go
 を用意している。また,eShotは敵機の弾のグラフィック番号を入れておく変数である。

変数名 意味
eShot_Go 敵機の8個の弾すべてが未発射状態になり,この変数に1を入れて,8個の弾を一斉に発射できる状態
になったことを表す。
8個の弾のうちどれかひとつでも発射状態(=画面上に弾が残っている)なら,まだ発射できない状態で
あるとして,この変数に0を入れておく。
eShot 敵機の弾のグラフィック番号を入れておく変数

 ※②の部分に関しては,下図の下に解説する。

array2.cpp
array2_code


②の部分は,主に

1. eShot_Go を1にして,取りあえず敵機が弾を発射可能としておく。

2. 最初のfor文
  敵機の各弾が,画面の左・右・上・下から飛び出していないかチェックして,飛び出している弾は未発射状態とする。
  そして,敵機の弾のどれかひとつでも弾が画面外にあったら eShot_Go を0にして,敵機が弾を撃てない状態である事を表す)

3. 次にif文
  敵機の弾が発射可能(eShot_Go が 1)なら,敵機の弾8個全てに関して,発射済みにし,座標を敵機の中心付近の座標に設定しておく。

4. そして再びfor文
  発射済みの敵機の弾は,画面上に表示されていなければならないので,画面に描写しておく。
  そして,敵機の弾の位置を進めておく。
  敵機の弾は,放射状に広がっていくように8方向で飛び出していく。その計算の為に,三角関数cos()とsin()を利用している。

    e_shots_x[j] = e_shots_x[j] + 6 * cos( j * (0.25 * 3.1415926) );
    e_shots_y[j] = e_shots_y[j] + 6 * sin( j * (0.25 * 3.1415926) );

   ・三角関数といっても難しく考える必要は無い。
   ・cos()関数は角度を与えて cos( 角度 )と使うと,原点から距離1だけ離れた場所のx座標を返してくれる。
   ・sin()関数は角度を与えて sin( 角度 )と使うと,原点から距離1だけ離れた場所のy座標を返してくれる。
  ので,それを利用させてもらっているだけである。   ただし, プログラミングの世界では,角度の単位として「ラジアン(radian)」を用いているので,cos(),sin( )関数にはラジアンで角度を
  与える必要がある。ラジアンの考え方と,我々が日常生活で使用している度(°, degree)からの換算について,下図で説明しよう。



 上図の最後の例2で,45度は 0.25πラジアン,つまり, (0.25 * 3.1415926) ラジアンであることがわかる。前述した今回の
ソースコードの,敵のj番目の弾の次の位置を計算する式

              e_shots_x[j] = e_shots_x[j] + 6 * cos( j * (0.25 * 3.1415926) );
              e_shots_y[j] = e_shots_y[j] + 6 * sin( j * (0.25 * 3.1415926) );

の中で,この値(45度をラジアンに換算した値)が使われていることが分かる。


では,この敵の弾の座標計算の考え方を詳しく見てみよう(下図)。

sincos
※前述したように,cos()関数とsin()関数に与える角度の値は,『角度(°)に円周率/180(ラジアン/度)をかけてラジアンに換算した数値』にする必要がある。
 ここでは,8方向に弾を出したいので,角度の刻みは 45度ずつ。45/180 は 1/4 で,0.25 となるので, ソースプログラム上では角度の刻みを 『 0.25 * 円周率』としている。
※距離としては6だけ進むようにしているので,6をかけている。
※なお,cos()関数とsin()関数といった数学の命令を使用するには,プログラムの最初の部分で
  #include <math.h>
としておく必要がある。

5. 敵機の描写と座標移動
 ・敵機の描写をした後,敵機の座標 ex, ey を更新している。

    ex = ex + 『敵機から自機までのx座標上の距離』 / 15;

  とすると,敵機は,x座標上で自機に近づく(1/15だけ距離を縮めてくる)。

     『敵機から自機までのx座標上の距離』 は 『自機のx座標 - 敵機のx座標』 なので,『x - ex』 となる。

  つまり

    ex = ex + (x - ex) / 15;

  となる。

 ・それだけでは芸が無いので,利用する毎にでたらめ(ランダム)な値を返してくれるDXライブラリの命令 GetRand() を使っている。
  GetRand( 100 ) と呼び出すと,この命令は 0 〜 100 までの値からどれかを適当に選んで返してくれる。
  そして,

    ex = ex + (x - ex) / (GetRand(200) + 15);

として,少し近づいてくる距離を『ゆらして』やっているわけである。
(一番速く近づくときは 『距離を1/15だけ縮める』ように近づき,一番遅く近づくときは 『距離を1/215だけ縮める』ように近づく)