「操作盤」フォームに「インベーダー生成」ボタンを作り、このボタンを押すと新しいインベーダーが次々に生成される、というプログラムに改変します。左のようにフォームにボタンを付け加え、次のような名前にしてください。
コンポーネント | Name プロパティ |
---|---|
「インベーダー生成」ボタン | ButtonGenerate |
今までは、インベーダーは4機 (ボスインベーダーなどを除く) と固定されていましたが、これから作り変えるプログラムでは、インベーダーの機数は特に定まっていません (実行中に何機でもインベーダーを作り出すことが出来るからです)。そのため、インベーダーを初期化する部分
Invader1.Construct; // インベーダー1を出現させる Invader2.Construct; // インベーダー2を出現させる Invader3.Construct; // インベーダー3を出現させる Invader4.Construct; // インベーダー4を出現させる
や、インベーダーを移動させる部分
Invader1.Move; // インベーダー1を動かす Invader2.Move; // インベーダー2を動かす Invader3.Move; // インベーダー3を動かす Invader4.Move; // インベーダー4を動かす
では、初期化文や移動文をいくつ書いていいか分からず、困ってしまいます。
このように、ある命令文を何度繰り返すか、が実行中でないと定まらない場合は、for 文 (や while 文) が適していましたね。しかし、Invader1, Invader2, Invader3, Invader4 という名前でインベーダーが用意 (宣言) されていても、このままでは for 文で使える形 (変数 i などを使って呼び出せる形) ではありません。そこで、各インベーダーの宣言
var
Invader1: TInvader;
Invader2: TInvader;
Invader3: TInvader;
Invader4: TInvader;
を次のように書き換えます。
var Invaders: Array of TInvader;
この1行で、Invaders[0], Invaders[1], Invaders[2], Invaders[3], …と、(0番から名付けられる) いくつものインベーダーを宣言したことになります。…ですが実際には、この命令だけで無限の機数のインベーダーのためのメモリを確保することは不可能なので、SetLength という手続きによって「何機分用意するか」を宣言する必要があります。
「表示」→「プロジェクト マネージャ」で、プロジェクトファイル「invader_game.exe」を右クリックして「ソース表示」を選び、プログラムを次のように変更しましょう。
begin Application.Initialize; Application.CreateForm(TFormControl, FormControl); Application.CreateForm(TFormDisplay, FormDisplay); SetLength(Invaders, 4); // 「インベーダーは4機」と宣言 Invaders[0] := TInvader.Create; Invaders[1] := TInvader.Create; Invaders[2] := TInvader.Create; Invaders[3] := TInvader.Create; Bullet1 := TBullet.Create; InvaderBoss := TInvaderBoss.Create; Application.Run; end.
今の練習問題で変更した部分を、更に for 文を使った形へと改良しましょう。
var i: Integer; begin Application.Initialize; Application.CreateForm(TFormControl, FormControl); Application.CreateForm(TFormDisplay, FormDisplay); SetLength(Invaders, 4); // 「インベーダーは4機」と宣言 for i :=0 to 3 do begin Invaders[i] := TInvader.Create; end; Bullet1 := TBullet.Create; InvaderBoss := TInvaderBoss.Create; Application.Run; end.
上の練習問題と同様に
と見なして for 文で書きかえるべき場所が、このプログラムには2ヶ所残っています。この2ヶ所を探し出して修正し、プログラムを実行してください。
これで下準備は終わり、いよいよインベーダーを増やすことが出来ます。例えば、5機目のインベーダーを生成するためには、生成したい場所 (例えば「インベーダー生成」ボタンの OnClickイベントハンドラ) で次のような命令を書き込むことになるでしょう。
SetLength(Invaders, 5); // 「インベーダーは5機」と宣言 Invaders[4] := TInvader.Create; Invaders[4].Construct; // インベーダー5を出現させる
上の例では、5機目のインベーダーを作り出すことは出来ますが、6機目以降のインベーダーを作り出すことは出来ません。6機目以降のインベーダーも作り出せるように変更しましょう。なお、「今までにいくつのインベーダーが生成されたか」は、Length(Invaders) で分かります。
「インベーダー生成」ボタンのイベントハンドラは、次のようにします。
// 「インベーダー生成」ボタン procedure TFormControl.ButtonGenerateClick(Sender: TObject); begin SetLength(Invaders, Length(Invaders) + 1); // 「インベーダーは1機増える」と宣言 Invaders[Length(Invaders) - 1] := TInvader.Create; Invaders[Length(Invaders) - 1].Construct; // 新しいインベーダーを出現させる end;
最後に、タイマーが時を刻む毎にインベーダーを移動させる部分の for 文の繰り返し回数を修正しておきます。
// タイマーが時間を刻むごとに procedure TFormControl.TimerMainTimer(Sender: TObject); var i: Integer; begin for i := 0 to Length(Invaders) - 1 do begin Invaders[i].Move; // インベーダーを動かす end; InvaderBoss.RandomMove; // ボスインベーダーを動かす Bullet1.Move; // 弾を動かす end;
これで、プログラム実行中でも「インベーダー生成」ボタンを押すことによってインベーダーを増やすことが出来るようになりました。