もぐら叩きを作ってみよう その3

このページ内のプログラムは、「その1」「その2」で作成してきたプロジェクトとは、別のプロジェクトにして下さい。)つまり、今まで作成してきたプログラムは、このページ内では使用しません(「その4」から使用することになります)。

もぐら叩きを作ってみよう その3です。今回は、プログラムをちょっと離れて図形の重なりについてやってみたいと思います。もぐら叩きでは、もぐらとマウスカーソルが重なった時にクリックすれば、モグラを叩いたことになります。これは言い換えると、もぐらとマウスカーソルが重なっていなければクリックしても、もぐらを叩いたことにはならないことと同じです。

もぐらとマウスカーソル、言い換えると図形と図形の重なりをプログラムで表現しなければなりません。図形が重なっていることを、どのように記述すればよいのでしょう。下の図を見てください。

この図のように図形を重ねるパターンは全部で4種類あります。これらの4つのパターンには、共通するものがあります。それぞれの図形に、一本の赤い線を引いてみました。この線に注目してください。

よく見てみると、規則性があります。1番の図形の赤い線は必ず、2番の図形の赤い線より左にあります。言い換えると、1番の図形の左側は、2番の図形の右側より必ず左にあるということです。これのどこに規則性があるのかというと、実は、他の辺にも同様の規則性があるのです。今度は1番の図形の右側と2番の図形の左側に注目してください。1番の図形の右側は、必ず2番の図形の左側より、右にあります。他の辺も同様に、1番の上側は2番の下側より必ず上にあります。1番の下側は、2番の上側より必ず下にあります。

つまり、この4つの条件を満たせば必ず2つの図形は、重なっているということになります。早速これをプログラムで書いてみましょう。ここで、1番の図形の左上の座標を( x1, y1 ), 2番の左上の座標を( x2, y2 )とします。また、2つの図形の大きさをそれぞれ 10 * 10 ( 縦 * 横 )とします。そうしますと、上の4つの条件は、以下のように書けます。

var
  x1, y1, x2, y2: Integer;
begin
  if (x1 < x2+10) and (x1+10 > x2) and
     (y1 < y2+10) and (y1+10 > y2) then
  begin
    // 図形が重なっていれば、ここに記述したプログラムが実行されます。
  end
  else
   // 図形が重なっていなければ、ここのプログラムが実行されます。
end;

注意しなければならないのは、フォームにおける座標は、左上を( 0, 0 )として、右に行くほど x が増え、下に行くほど y が増えます。説明だけだと分かりにくいので、座標を表示させるプログラムを書いてみましょう。フォームにラベルを貼り付けて、オブジェクトインスペクタでフォームを選択し、イベントページの OmMouseMove の右側の空白をダブルクリックして、以下のコードを書いてくさい、マウスを移動させると、ラベルにマウスの現在の座標が表示されます。

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  Label1.Caption := Format('X: %d  Y: %d', [X, Y]);
end;

実際に、実験してみよう。

それではフォームに実際に図形を描いて、その図形とマウスカーソルが重なっているかを判定するプログラムを書いてみましょう。少し注意しなければならない点は、フォームにおける座標 ( x , y ) は、左上角を ( 0, 0 ) とし右へ行くほど x が増加し、下へ行くほど y が増加します。そして、マウスカーソルには、大きさがありません。マウスカーソルは、矢印の先端のみが有効となっていますので、図形とマウスカーソルの重なりとは、具体的には図形と図形の重なりではなく、図形内に点(マウスカーソルの先端)が入っているかどうかを判定することになります。

それでは、まず図形をフォームに描画してみましょう。ボタンを一つ貼り付けて下さい。プログラムは以下のようになります。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  // 描画する四角形の左上角の座標と、図形の幅、高さを保持するレコード
  TMyRec = record
    Left: Integer;
    Top : Integer;
    Height: Integer;
    Width: Integer;
  end;

var
  MyRec: TMyRec;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // 四角形の座標を決定します。
  MyRec.Left   := 100;
  MyRec.Top    := 100;
  MyRec.Width  := 100; // 幅を 100 に設定
  MyRec.Height := 50;  // 高さを 50 に設定
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // キャンバスのブラシを青にします。
  Canvas.Brush.Color := clBlue;

  // キャンバスに四角を描きます。
  Canvas.Rectangle(MyRec.Left, MyRec.Top,
    MyRec.Left+MyRec.Width, MyRec.Top+MyRec.Height);
end;
  
end.

F9 キーを押してプログラムを実行し、フォームに貼り付けたボタンを押してみてください。フォームに四角形が描画されます。

四角形の左上角の座標に対して、幅、高さをそれぞれ足してやる事で、四角形の右下角の座標が計算できる事になります。そして、冒頭で解説した図形の重なりをプログラムします。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TMyRec = record
    Left: Integer;
    Top : Integer;
    Height: Integer;
    Width: Integer;
  end;

var
  MyRec: TMyRec;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // 四角形の座標を決定します。
  MyRec.Left   := 100;
  MyRec.Top    := 100;
  MyRec.Width  := 100; // 幅を 100 に設定
  MyRec.Height := 50;  // 高さを 50 に設定
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // キャンバスのブラシを青にします。
  Canvas.Brush.Color := clBlue;

  // キャンバスに四角を描きます。
  Canvas.Rectangle(MyRec.Left, MyRec.Top,
    MyRec.Left+MyRec.Width, MyRec.Top+MyRec.Height);
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  // マウスカーソルと描画した四角形が重なっているかを調べます。
  if (x < MyRec.Left+MyRec.Width) and
     (x > MyRec.Left) and
     (y < MyRec.Top+MyRec.Height) and
     (y > MyRec.Top) then
  begin
    ShowMessage('四角の中です')  // マウスカーソルが四角の中にあれば
  end
  else
    ShowMessage('四角の外です'); // マウスカーソルが四角の外にあれば
end;

end.

マウスカーソルが図形内にあれば、「四角形の中です」とメッセージボックスが表示されます。


up next
Last update: 2002/11/29