Search code examples
delphidelphi-7collision-detection

How to test if a shape and a panel are at the same location


The idea is that you must shoot the panel. So the panel will be set to a random location at the top of the screen and then move down to the bottom of the screen. You must shoot the panel with the shapes before it reaches the bottom. But I dont know how to test if the created shape is at the location of the panel to reset the panel. At the moment this is my code but the if tests false.

unit Unit1;

interface

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

const
  MaxRays=100;
  RayStep=8;
type
   TForm1 = class(TForm)
   Panel1: TPanel;
    Timer1: TTimer;
    Timer2: TTimer;
    Button1: TButton;
    Shape1: TShape;
    Timer3: TTimer;
    Image1: TImage;
    procedure Timer2Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
      MousePos: TPoint; var Handled: Boolean);
    procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
       MousePos: TPoint; var Handled: Boolean);
     procedure Timer3Timer(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
    Rays:array[0..MaxRays-1] of TShape;

   public
   procedure StartPanelAnimation1;
   procedure DoPanelAnimationStep1;
   function  PanelAnimationComplete1: Boolean;
   { Public declarations }
  end;

var
  Form1: TForm1;

implementation
 var key : char;
{$R *.dfm}

{ TForm1 }



 { TForm1 }

 procedure TForm1.DoPanelAnimationStep1;
begin
Panel1.Top := Panel1.Top+1;
end;

function TForm1.PanelAnimationComplete1: Boolean;
begin
 Result := Panel1.Top=512;
end;

procedure TForm1.StartPanelAnimation1;
begin
  Panel1.Top := 0;
  Timer1.Interval := 1;
  Timer1.Enabled := True;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
   DoPanelAnimationStep1;
   if PanelAnimationComplete1 then
    StartPanelAnimation1;
   if (shape1.Top < panel1.Top) and (shape1.Left < panel1.Left+104) and (shape1.Left >       panel1.Left)   then
   begin
    startpanelanimation1;
    sleep(10);
   end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 button1.Hide;
  key := 'a';
  timer2.Enabled := true;
  StartPanelAnimation1; 
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
 shape1.Visible := false;
 timer2.Enabled := false;
 end;

procedure TForm1.FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
   begin
image1.Left := image1.Left-10;
end;

 procedure TForm1.FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
    begin
    image1.Left := image1.Left+10;
   end;

procedure TForm1.Timer3Timer(Sender: TObject);
var
  i:integer;
begin
  for i:=0 to MaxRays-1 do
    if Rays[i]<>nil then
    begin
      Rays[i].Top:=Rays[i].Top-RayStep;
      if Rays[i].Top<0 then FreeAndNil(Rays[i]);
    end;
end;


procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
   var
   i:integer;
begin
  i:=0;
  while (i<MaxRays) and (Rays[i]<>nil) do inc(i);
  if i<MaxRays then
   begin
    Rays[i]:=TShape.Create(Self);
    Rays[i].Shape:=stEllipse;
    Rays[i].Pen.Color:=clRed;
    Rays[i].Pen.Style:=psSolid;
    Rays[i].Brush.Color:=clYellow;
    Rays[i].Brush.Style:=bsSolid;
    Rays[i].SetBounds(X-4,Y-20,9,41);
    Rays[i].Parent:=Self;
    end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i:integer;
begin
  for i:=0 to MaxRays-1 do Rays[i]:=nil;
end;

end.

I have tried what @NGLN has said but when I i click the the mouse button the shape moves like 10 pixels then stops, when it stops the panel which was moving down normally is now moving like crazy at the top of the screen changing its left position but the top position stays 0.

Here Is the new code

unit Unit1;

interface


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

  const
  MaxRays=100;
  RayStep=8;
type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Timer1: TTimer;
    Timer2: TTimer;
    Button1: TButton;
    Shape1: TShape;
    Timer3: TTimer;
    Image1: TImage;
    Timer4: TTimer;
    procedure Timer2Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
      MousePos: TPoint; var Handled: Boolean);
    procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
      MousePos: TPoint; var Handled: Boolean);
    procedure Timer3Timer(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    Rays:array[0..MaxRays-1] of TShape;
  public
   procedure StartPanelAnimation1;
   procedure DoPanelAnimationStep1;
   function  PanelAnimationComplete1: Boolean;
   function EllipticShapeIntersectsPanel(Shape: TShape; Panel: TPanel): Boolean;
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
 var key : char;
{$R *.dfm}

{ TForm1 }



{ TForm1 }

procedure TForm1.DoPanelAnimationStep1;
begin
Panel1.Top := Panel1.Top+1;
end;

function TForm1.PanelAnimationComplete1: Boolean;
begin
 Result := Panel1.Top=512;
end;

procedure TForm1.StartPanelAnimation1;
var left : integer;
begin
  Panel1.Top := 0;
  randomize;
  left := random(clientwidth-105);
  panel1.Left := left;
  Timer1.Interval := 1;
   Timer1.Enabled := True;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
 var I: Integer;
begin
 DoPanelAnimationStep1;
  if PanelAnimationComplete1 then
    StartPanelAnimation1;
   I := 0;
  while (Rays[I] <> nil) and (I < MaxRays)  do
  begin
    if EllipticShapeIntersectsPanel(Rays[I], Panel1) then
    Inc(I);
    startpanelanimation1;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 button1.Hide;
 key := 'a';
 timer2.Enabled := true;
 StartPanelAnimation1;
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
 shape1.Visible := false;
 timer2.Enabled := false;
end;

procedure TForm1.FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
image1.Left := image1.Left-10;
end;

procedure TForm1.FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
 image1.Left := image1.Left+10;
end;


procedure TForm1.Timer3Timer(Sender: TObject);
var
  i:integer;
begin
  for i:=0 to MaxRays-1 do
    if Rays[i]<>nil then
    begin
      Rays[i].Top:=Rays[i].Top-RayStep;
      if Rays[i].Top<0 then FreeAndNil(Rays[i]);
    end;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
 var
  i:integer;
  left : integer;
  top : integer;
begin
  i:=0;
  while (i<MaxRays) and (Rays[i]<>nil) do i:= i+10;
  if i<MaxRays then
   begin
    Rays[i]:=TShape.Create(Self);
    Rays[i].Shape:=strectangle;;
    Rays[i].Pen.Color:=clRed;
    Rays[i].Pen.Style:=psSolid;
    Rays[i].Brush.Color:=clred;
    Rays[i].Brush.Style:=bsSolid;
    left := image1.Left+38;
    top := image1.Top-30;
    Rays[i].SetBounds(left,top,9,33);
    Rays[i].Parent:=Self;
   end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 Screen.Cursor:=crNone;
end;

function TForm1.EllipticShapeIntersectsPanel(Shape: TShape;
  Panel: TPanel): Boolean;
var
  ShapeRgn: HRGN;
begin
  with Shape.BoundsRect do
    ShapeRgn := CreateEllipticRgn(Left, Top, Right, Bottom);
  try
    Result := RectInRegion(ShapeRgn, Panel.BoundsRect);
  finally
    DeleteObject(ShapeRgn);
  end;
end;

end. 

Solution

  • Since your shapes are elliptical, create a temporarilly region and determine intersection with a rectangle with RectInRegion:

    function EllipticShapeIntersectsPanel(Shape: TShape; Panel: TPanel): Boolean;
    var
      ShapeRgn: HRGN;
    begin
      with Shape.BoundsRect do
        ShapeRgn := CreateEllipticRgn(Left, Top, Right, Bottom);
      try
        Result := RectInRegion(ShapeRgn, Panel.BoundsRect);
      finally
        DeleteObject(ShapeRgn);
      end;
    end;
    

    (If the shapes are rectangular, then you can use the routine of Darthman.)

    Now feed each ray in your array to this routine:

    procedure TForm1.Timer2Timer(Sender: TObject);
    var
      I: Integer;
    begin
      ...
      I := 0;
      while (Rays[I] <> nil) and (I < MaxRays)  do
      begin
        if EllipticShapeIntersectsPanel(Rays[I], Panel1) then
          // Do what you want to do
        Inc(I);
      end;
    end;