-1

I'm making my own version of Space Invaders for my A Level project and I am stuck with the collision detection. I need to detect collision when the bullet hits one of the invaders and I'm really stuck.

The invaders currently are stored in a 2d array and move on a timer, the code for this is as follows:

for Row:=1 to 5 do
begin
frmGame.Canvas.FillRect(WaveArea)
for Column:=1 to 11 do
  begin
    frmGame.Canvas.Draw(30+Column*50+x, 180 Images[1].Picture.Graphic);
    frmGame.Canvas.Draw(30+Column*50+x, 230 Images[2].Picture.Graphic);
  end;
 x:=x+xShift;
end;
if x>500 then
 tmrMoveInvaders.Enabled:=False;

The collision code which I have written does not work but I am not sure why. It could be the way in which the images are loaded onto the form by using a 2D array but I'm not sure.

The code for the collision procedure is:

Procedure Collision(img:TImage);
Var
 TargetLeft,BulletLeft:integer;
 TargetRight,BulletRight:integer;
 TargetTop,BulletTop:integer;
 TargetBottom,BulletBottom:integer;
 Hit:boolean;

begin
 with frmGame do
  hit:=true;
  TagetLeft:=img.Left;
  BulletLeft:=shpBullet.Left;
  TargetRight:=img.Left+46; //left + width of the image
  BulletRight:=shpBullet.Left+8;
  TargetTop:=img.Top;
  BulletTop:=shpBullet.Top;
  TargetBottom:=img.Top+42; //top + height of image
  BulletBottom:=shpBullet.Top+15;

  if (TargetBottom < BulletTop) then hit:=false;
  if (TargetTop > BulletBottom) then hit:=false;
  if (TargetRight < BulletLeft) then hit:=false;
  if (TargetLeft > BulletRight) then hit:=false;
  if not img.Visible then hit:=false;

  if hit=true then
   img.Visible:=false;

Any help would be greatly appreciated.

user2180030
  • 17
  • 1
  • 5
  • What is the code expected to do? How does it fail to meet expectations? – David Heffernan Apr 15 '13 at 18:56
  • The code is meant to detect when the bullet shape overlaps with the invader image and then not show the image which has been hit. What currently happens is that the bullet goes straight through the invader image but instead of not showing the image the bullet just makes a line through the invader where is has passed. – user2180030 Apr 15 '13 at 19:00
  • What attempts did you make to debug it? – David Heffernan Apr 15 '13 at 19:01
  • This code worked fine when I had the images pasted on the form before run-time but then I loaded them onto the form using an array at run time and now it doesn't work and I really have no idea why. Been thinking about it for a few hours and I don't know what to do – user2180030 Apr 15 '13 at 19:04
  • 1
    Well, do some debugging. You know how to use the debugger right? – David Heffernan Apr 15 '13 at 19:09
  • 2
    Also I suggest solving such problems on paper. Graph paper. Get a pencil. – Warren P Apr 15 '13 at 22:04
  • 1
    I don't think this code even compiles. You've got `TagetLeft` in there, while the declared variable is called `TargetLeft` – Wouter van Nifterick Apr 16 '13 at 00:46
  • The usual problem with collision detection is when one of the objects moves too fast relative to the other. This can lead to missing the collision. Check the answer to this [question](http://stackoverflow.com/questions/345838/ball-to-ball-collision-detection-and-handling) – Guillem Vicens Apr 16 '13 at 06:17

1 Answers1

3

Your collision math is sound: when one of those four checks is true, then indeed there is no hit. So you need to debug, because obviously something else ís wrong.

Start to debug logically first:

  • Q: What am I checking exactly? A: The position of an Image and the bullet.
  • Q: What is the position of the bullet? A: It is the BoundsRect of the shape control which I see on my form. Can't be wrong.
  • Ok.
  • Q: What is the position of the image? A: The same: it is the bounds rect of the Image component which I see on my form.
  • Q: Really? A: Yeah... oh wait; I paint the images myself!!! (Huh, why??)
  • Q: Well, could that be the cause? A: Uhm, possibly...?

In short: in your Collision routine, you assume that the image controls in your 2D array contain information about their position on the form. But I suspect they're not even childs of the form, let alone have any Left and Top properties set at all, because you draw them manually with Canvas.Draw.

Conclusion: calculate the position of an image as you do in your paint routine. Or set the Parent property of each image, and rewrite the code in your update routine by not drawing the images' graphics but instead reposition the image components in the array by setting Left and Top.

Remarks:

  • I completely agree with Wouter: your code does not compile due to many, many syntax errors. Please ensure to place the true compiling code here on StackOverflow, preferably by copy-pasting it directly from your source editor.
  • You can simplify your collision detection with the use of IntersectRect, as follows:

    const
      ColCount = 11;
      RowCount = 5;
    
    type
      TCol = 0..ColCount - 1;
      TRow = 0..RowCount - 1;
    
      TGameForm = class(TForm)
      private
        FBullet: TShape;
        FTargets: array[TCol, TRow] of TImage;
        procedure CheckCollisions;
      end;
    
    implementation
    
    {$R *.dfm}
    
    procedure TGameForm.CheckCollisions;
    var
      Col: TCol;
      Row: TRow;
      R: TRect;
    begin
      for Col := Low(TCol) to High(TCol) do
        for Row := Low(TRow) to High(TRow) do
          if IntersectRect(R, FTargets[Col, Row].BoundsRect, FBullet.BoundsRect) then
            FTargets[Col, Row].Visible := False;
    end;
    
  • Try to work with an array of graphics instead of images: FTargets: array[TCol, TRow] of TGraphic;

  • Or better, in case of all targets being the same image: make it a 2D array of Boolean, indicating whether the target at that coordinate is hit or not.
  • Stop using the global form variable (frmGame). And stop right NOW!
  • Make all routines methods of the form class, as shown above.
  • Make all global variables private fields of the form class, as shown above.
NGLN
  • 43,011
  • 8
  • 105
  • 200