delphi中的碰撞检测(pascal)

时间:2013-04-15 18:55:11

标签: arrays delphi collision-detection pascal

我正在为我的A Level项目制作我自己的太空入侵者版本,我仍然坚持使用碰撞检测。当子弹击中其中一个入侵者时,我需要检测到碰撞,我真的被困住了。

入侵者目前存储在一个二维数组中,并在计时器上移动,其代码如下:

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;

我写的碰撞代码不起作用,但我不确定原因。它可能是使用2D数组将图像加载到表单上的方式,但我不确定。

碰撞程序的代码是:

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;

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:3)

你的碰撞数学是合理的:当这四个检查中的一个为真,那么确实没有命中。所以你需要调试,因为显然别的东西是错的。

首先开始逻辑调试:

  • 问:我究竟在检查什么?答:图像和子弹的位置。
  • 问:子弹的位置是什么?答:这是我在表单上看到的形状控件的BoundsRect。不能错。
  • 确定。
  • 问:图像的位置是什么?答:相同:它是我在表单上看到的Image组件的bounds rect。
  • 问:真的吗? A:是啊......等等;我自己画图像! (嗯,为什么?)
  • 问:那可能是原因吗? A:嗯,可能......?

简而言之:在碰撞例程中,您假设2D数组中的图像控件包含有关它们在窗体上的位置的信息。但我怀疑他们甚至不是这种形式的孩子,更不用说设置任何LeftTop属性了,因为你用Canvas.Draw手动绘制它们。

结论:像在油漆程序中一样计算图像的位置。或者设置每个图像的Parent属性,并通过不绘制图像的图形来重写更新例程中的代码,而是通过设置LeftTop重新定位阵列中的图像组件

说明:

  • 我完全同意Wouter:由于许多语法错误,您的代码无法编译。请确保在StackOverflow上放置真正的编译代码,最好直接从源代码编辑器中复制粘贴。
  • 您可以使用IntersectRect简化碰撞检测,如下所示:

    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;
    
  • 尝试使用图形数组而不是图像:FTargets: array[TCol, TRow] of TGraphic;

  • 或者更好的是,如果所有目标都是相同的图像:将其设为Boolean的2D数组,指示该坐标处的目标是否被命中。
  • 停止使用全局表单变量(frmGame)。现在停止吧!
  • 制作表单类的所有例程方法,如上所示。
  • 将所有全局变量设置为表单类的私有字段,如上所示。