プログラム実行中はインベーダーフォームやボスインベーダーフォームは表示されなくなりましたが、プログラム設計中はまだフォーム (方眼のついたフォーム) が表示されます。
ボスインベーダーフォームの上で右クリックし、「エディタで表示」を選んでください。
すると、次のようなコードが表示されます。(あなたのインベーダープログラムでは、一部の値がこれと違うかも知れませんが、気にする必要はありません。)
object FormInvaderBoss: TFormInvaderBoss Left = 710 Top = 449 Width = 377 Height = 340 Caption = 'ボスインベーダー' Color = clBtnFace Font.Charset = SHIFTJIS_CHARSET Font.Color = clWindowText Font.Height = -12 Font.Name = 'MS Pゴシック' Font.Style = [] OldCreateOrder = False Visible = True PixelsPerInch = 96 TextHeight = 12 end
今までオブジェクトインスペクタで設定したプロパティの内容は、このような形で記憶されています。(そして、このコードを直接書き換えると、例えば「Caption = 'ボスインベーダー'」を「Caption = '大侵略者'」と書き換えるとフォームもその通りに変更されます。)
そして、このコードの上の方を見ると、ファイル名が「invader_boss.dfm」となっていることがわかります。つまり、「invader_boss.dfm」というファイルがインベーダーフォームのデザインをつかさどっているのです。"dfm" は "Delphi ForM" ファイルの略です。各プロジェクトのフォルダの中に「.dfm」で終わるファイルが存在することは、Delphi を使い始めた頃から知ってますね。(確認したらコード上で右クリックし、「フォームとして表示」を選んで元の状態に戻してください。)
ですが、実行中にはインベーダーフォームは使われていないため、このファイルも不要です。
これからこの invader_boss.dfm ファイルを削除します。まずは、この invader_boss.dfm ファイルを参照している部分の記述を消していき、最後に invader_boss.dfm ファイルを削除します。
(1) invader_boss ユニットの中ごろにある {$R *.DFM} という行 (下の下線部) を削除してください。
implementation uses display, bullet; {$R *.DFM} // 「乱数移動」ボタン procedure TFormInvaderBoss.RandomMove; var
※ {$R *.DFM} は一見コメントのように見えますが、実は dfm ファイルを見つけて実行ファイルにリンクさせる命令 (コンパイラ指令といいいます) だったのです。これを削除すると、dfm ファイルがあってもフォームが作成されません。
(2) プロジェクトファイル (開き方は 11-5 の【練習問題】を参照すること) の次の部分を削除してください。
uses Forms, control in 'control.pas' {FormControl}, display in 'display.pas' {FormDisplay}, invader in 'invader.pas' {FormInvader}, bullet in 'bullet.pas' {FormBullet}, invader_boss in 'invader_boss.pas' {FormInvaderBoss};
(3) これで、invader_boss.dfm ファイルを削除することができます。「ファイル」→「すべて閉じる」で作成中のプログラムを一旦閉じ、invader_boss.dfm ファイルを削除し、「ファイル」→「プロジェクトを開く」で再度開いてみてください。特に、その状態から「表示」→「プロジェクトマネージャ」を選ぶと、他のユニットとの違いがよくわかります。
この invader_boss.dfm ファイルは、「ファイル」→「フォームの新規作成」を選んだ段階で自動的に作られたものです。もし最初からフォームのないユニットを作るなら、「ファイル」→「フォームの新規作成」ではなく「ファイル」→「新規作成」→「ユニット」を選びます。
こうして作られたユニットは、非常にあっさりしています。ここに、先ほどのプログラム
unit invader_boss; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin, Invader; type TFormInvaderBoss = class(TFormInvader) private { Private 宣言 } protected procedure Draw; override; public { Public 宣言 } procedure RandomMove; virtual; end; var FormInvaderBoss: TFormInvaderBoss; implementation uses display, bullet; // 「乱数移動」ボタン procedure TFormInvaderBoss.RandomMove; var NewSpeed: Integer; begin NewSpeed := GetSpeed + Random(7) - 3; SetSpeed(NewSpeed); Move; end; procedure TFormInvaderBoss.Draw; begin FormDisplay.ImageField.Canvas.Pen.Color := clRed; // 赤でインベーダを描く FormDisplay.ImageField.Canvas.MoveTo(GetX, GetY - 3); FormDisplay.ImageField.Canvas.LineTo(GetX - 5, GetY + 3); FormDisplay.ImageField.Canvas.LineTo(GetX + 5, GetY + 3); FormDisplay.ImageField.Canvas.LineTo(GetX, GetY - 3); end; end.
を書き込むとよいのです。
なお、最初の uses の部分は
uses
Graphics, Invader;
と簡単にしても構いません。
uses の部分は、「このユニットは〜という他のユニットやシステムの機能を使うことがあります」という宣言です。「ファイル」→「フォームの新規作成」を選んだ段階で Delphi が「後で色々使うかもしれない」と考えて勝手に色々宣言しているのですが、そのままでは余計なものが含まれています。
このプログラムでは、下の2つさえ宣言してあれば動きます。
必要な宣言 | 理由 |
---|---|
Graphics | FormDisplay のグラフィックスを操作しているため |
Invader | Invader クラスから継承しているため |
invader ユニットも同様に単純なユニットにしてください。
すでにインベーダーフォームが存在しないのに FormInvader1などの名前はふさわしくありません。FormInvader1 〜 FormInvader4 をそれぞれ Invader1 〜 Invader4 に、また TFormInvader を TInvader に変えてください。
ボスインベーダーに関しても同様に変えてください。
bullet ユニットも同様に単純なユニットにしてください。なお、上の練習問題と同様に、FormBullet を Bullet1 に、TFormBullet を TBullet にしてください。
今までは、フォームとユニットは同じものを指していましたが、実は別物です。最終的に出来上がる実行ファイルに対応するのがプロジェクトであり、そのプロジェクトに直接乗っかっているのがユニットです。1つのユニットには1つのフォームをつけることができます (もちろんフォームがないユニットも作れます)。これを図にすると次のようになります。
TInvader や TBullet のように、型となるもののことをクラスと呼びます。Invader1 や Bullet1 のように、クラスから作られる各々の実体をオブジェクトと呼びます。