では、判りやすい(たぶん)ように、順番に説明していきたいと思います。
まず、構造化プログラムという事で、必要な変数等をグローバル変数として宣言してやります(ソースの出来るだけ上に書く。
こうする事で、どこでも(どの自作関数内でも)これらの変数を参照する事が出来るようになります。
今まで、プレイヤーの座標はWinMain関数内でcx,cyと宣言し、それらを使用していましたが、今回は構造体(_player)として
宣言します。_bullet構造体は、弾の処理に使用します。今回使う変数はとりあえず、使用・未使用を表すフラグ(enable)と
座標(x,y)と、進む方向(angle)だけです。
では、一番最初に実行するWinMain関数を見てみましょう。
いやぁ、今まではここ(↑)にひたすら書いていたので、今回のプログラムは結構すっきり見えますね。
InitWindow()はウィンドウを作成する処理を書いてあるだけの自作関数なので解説省略。
で、DirectDrawを初期化したらInitGame();を呼び出していますね?これはゲームに必要な処理を先にしておく自作関数です。中を見てみましょう。

まず、作業用サーフェイス(lpWork)にキャラの画像を読み込んでおきます(左の絵)。
で、_bullet構造体のメンバ変数「enable」を0に設定しておきます(全て)。enableが0だったら、
その構造体は使用していないという事にします。
で、ここの処理が終わると、処理はWinMainの方へ戻って、次はGameLoop();を呼び出していますよね?
この関数はゲームのループ用の自作関数です。コードは次のようになっています。
whileの中の最初と最後のWaitSet()、Wait()については既にやっているので解説省略。
で、まずMovePlayer()関数を呼び出していますよね?こいつはキー入力により自機を動かす処理をする
自作関数です。
この関数内でやっていることは
第5回で説明したので、みりゃ判りますね?(爆
ここの処理が終わったら、GameLoopの方へ戻って、次にShoot()関数が呼ばれています。
Shoot()関数では、スペースキーが押されているか判定し、押されていれば弾を作成します。
ここでは、シューティングゲームで使うような、押しっぱなしでも連射できる処理をやります。
ここでは、ちょっとした工夫が必要ですかね。スペースキーが押されていた場合に弾を作成するだけでは、
押している間、毎回弾が作成されてしまいますよね?シューティングゲームのように、一定間隔で弾を撃ちたい場合は、
一つ変数を用意し(今回はplayer.renda)、スペースキーが押されている間はこの変数に1を足し、10になったら0に戻してやります。
で、この変数が0の時だけ弾を作成すれば、処理的には10ループに1回弾を発射する事になりますよね?
さて、ここで極端な例を挙げてみます。この弾を出す間隔が10では無く、1000だとしましょう。
普通、ゲームで発射キーを押しっぱなしにする場合、発射キーを押した瞬間に弾が発射され、一定間隔で弾がでますよね?
で、もし変数「player.renda」が仮に500で止まっていたらどうでしょう。発射キーを押しても、player.rendaは0でないため、
しばらく発射されませんね?これではマズイ(と思う)ので、発射キーが押されていない時、player.rendaが0で無い場合には、
player.rendaに1を足し、ある数を越えたら0にする、といった処理を付け加えてやります。こうすれば、発射キーを離している間でも
player.rendaの値が変化するので、発射キーを離し、しばらくして発射キーを押した瞬間に、弾を発射させる事が可能となります。
ついでですが、発射キーが押されていない時にplayer.rendaを0にすると、いつでも発射キーを押した瞬間に弾が出せます(実際にやってみて下さい)。
ここの関数内では弾を作成する時にCreateBullet( x座標 , y座標 , 角度(0〜359) )自作関数を呼び出しています。
ではどういった処理をしているのか見てみましょう。
さて、初めの方で呼び出したInitGame()内では_bullet構造体の全てのenableを0にし、未使用データとしましたね?
ですから、ここ(CreateBullet)では、構造体の配列の0番からBMAX-1(今回は99)までを順に参照し、
enableが0(つまり未使用となっているデータ)を探します。
そんでもって、空いているデータが見つかったら、その番号の構造体に情報を詰め込んでやります。
最後にenableを1とし、no番の構造体を使用データという事にしていますよね?
ですから、次にCreateBullet関数内で空いているデータを順に探した時も、no番のenableは0では無いので
上から新しくデータが詰められる事はありません。
でShoot()関数へ戻り、GameLoop()の方へ戻り、次にMoveBullet()を呼び出しています。
ここでは、構造体_bulletの配列を0から順番に参照し、enableが0でないデータ(つまり使用しているデータ)だけを処理します。
角度による移動自体は
第4回で説明したので省略。
そして、画面外に出たらenableを0にし、未使用データとしてやります。
GameLoop()に戻り、次にShow()が呼び出されます。これは、ディスプレイに一連の表示をする
自作関数です。
コードを見てみましょう。
まぁ、ここは見りゃ判りますね(爆
弾は使用しているものだけ表示してやります。
とりあえず、これで説明は終わりです(^^;
今回のプログラムの流れを図で表すと、こんな感じになるのかも

矢印は関数の呼び出しです。