-1

我正在为我的 A Level 项目制作自己的 Space Invaders 版本,但我被碰撞检测困住了。当子弹击中一名入侵者并且我真的被卡住时,我需要检测碰撞。

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

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;

我写的碰撞代码不起作用,但我不知道为什么。这可能是使用二维数组将图像加载到表单上的方式,但我不确定。

碰撞过程的代码是:

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;

任何帮助将不胜感激。

4

1 回答 1

3

您的碰撞数学是正确的:当这四个检查之一为真时,确实没有命中。所以你需要调试,因为显然还有其他问题。

先从逻辑上开始调试:

  • 问:我在检查什么?A:图像和子弹的位置。
  • 问:子弹的位置是什么?答:这是BoundsRect我在表单上看到的形状控件。不能错。
  • 好的。
  • 问:图像的位置是什么?答:同样:它是我在表单上看到的 Image 组件的边界矩形。
  • 问:真的吗?A:是的……哦等等;我自己画图!!!(咦,为什么??)
  • 问:嗯,这可能是原因吗?A:嗯,可能……?

简而言之:在您的 Collision 例程中,您假设 2D 数组中的图像控件包含有关它们在表单上的位置的信息。但我怀疑它们甚至不是表单的孩子,更不用说设置任何LeftTop属性了,因为你用Canvas.Draw.

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

评论:

  • 我完全同意 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;

  • 或者更好的是,如果所有目标都是同一张图像:将其设为 的 2D 数组Boolean,指示该坐标处的目标是否被击中。
  • 停止使用全局表单变量 ( frmGame)。并立即停止!
  • 制作表单类的所有例程方法,如上图。
  • 将所有全局变量设为表单类的私有字段,如上所示。
于 2013-04-16T19:24:12.560 回答