2个delphi问题,复制代码和随机化

时间:2016-03-16 10:37:25

标签: delphi

我在德尔福制作了我的第一个节目,它是一个太空入侵者。所以我有两个问题:

首先,如何将代码复制到每个对象?这就是我现在所拥有的:

    procedure TForm2.Timer1Timer(Sender: TObject);
begin
//Label2.Caption := IntToStr(Form2.ClientWidth);
//Label1.Caption := IntToStr(Shape2.Left + Shape2.Width);
  if smer = 1  then begin
  Shape2.Left:=Shape2.left+56;
  Shape3.Left:=Shape3.left+56;
  Shape4.Left:=Shape4.left+56;
  Shape5.Left:=Shape5.left+56;
  Shape6.Left:=Shape6.left+56;
    if Shape6.Left+Shape6.Width>Form2.ClientWidth then begin
    Shape2.Top:=Shape2.Top+56;
    Shape3.Top:=Shape3.Top+56;
    Shape4.Top:=Shape4.Top+56;
    Shape5.Top:=Shape5.Top+56;
    Shape6.Top:=Shape6.Top+56;
    smer:=0;
    end;
  end;
  if smer = 0  then begin
  Shape2.Left:=Shape2.left-56;
  Shape3.Left:=Shape3.left-56;
  Shape4.Left:=Shape4.left-56;
  Shape5.Left:=Shape5.left-56;
  Shape6.Left:=Shape6.left-56;
  if Shape2.Left<=0 then begin
    Shape2.Top:=Shape2.Top+56;
    Shape3.Top:=Shape3.Top+56;
    Shape4.Top:=Shape4.Top+56;
    Shape5.Top:=Shape5.Top+56;
    Shape6.Top:=Shape6.Top+56;
    smer:=1;
    end;
  end;
end;

procedure TForm2.Timer2Timer(Sender: TObject);
begin
 if MetakP.Visible=true then begin
    MetakP.Top:=MetakP.Top-11;
 end;
 if MetakN.Visible=true then begin
    MetakN.Top:=MetakN.Top+11;
 end;
 if MetakN.Top>Form2.Height then MetakN.Visible:=false;
 if MetakP.Top<=0 then begin
    MetakP.Left:=Image1.Left+16;
    MetakP.Top:=Image1.Top;
    MetakP.visible:=false;
    Let:=0;
 end;
 if (MetakN.left>=Image1.Left) or (MetakN.Left+MetakN.Width >= Image1.left) then begin    // da li je metak desno od kocke
    if MetakN.left<=Image1.Left+Image1.Width then begin // da li je metak levo od kocke
      If MetakN.Top<=Image1.Top+Image1.Height then begin  // da li je metak ispod kocke
        if MetakN.Top>=Image1.Top-Image1.Height then begin
          if MetakN.Visible=true then begin
            Image1.Visible:=false;//
            MetakN.Left:=Image1.Left+16;
            MetakN.Top:=Image1.Top;
            MetakN.visible:=false;
            Let:=0;
            gub:=gub+1;
            //Image1.Enabled:=false;
            end;
          end;
        end;
    end;
 end;
 if (MetakP.left>=Shape2.Left) or (MetakP.Left+MetakP.Width >= Shape2.left) then begin    // da li je metak desno od kocke
    if MetakP.left<=Shape2.Left+Shape2.Width then begin // da li je metak levo od kocke
      If MetakP.Top<=Shape2.Top+Shape2.Height then begin  // da li je metak ispod kocke
        if MetakP.Top>=Shape2.Top-Shape2.Height then begin
          if Shape2.Visible=true then begin
            Shape2.Visible:=false;//
            MetakP.Left:=Image1.Left+16;
            MetakP.Top:=Image1.Top;
            MetakP.visible:=false;
            Let:=0;
            pob:=pob+1;
            //Shape2.Enabled:=false;
            end;
          end;
        end;
    end;
 end;
end;

对所有形状都是如此。它基本上是一个hitbox检查。现在,这是很多代码,有没有办法让它分别适用于所有形状?

第二关,如何从随机形状中发射子弹?我有:

    procedure TForm2.Timer4Timer(Sender: TObject);
var r:integer;
var rr:string;
begin
  MetakN.Visible:=true;
  if Shape2.Visible=false then MetakN.Visible:=false;
  r:=2+random(5);
  rr:=IntToStr(r);
  MetakN.Top:=  Shape2.top+Shape2.Height;
  MetakN.Left:= Shape2.Left+Shape2.Width div 2;
end;

r应该被用作&#34; Shape [r] .top&#34;等等,但它不起作用。

1 个答案:

答案 0 :(得分:1)

程序由两部分组成。

  1. 代码
  2. Data structures
  3. 您只使用1.

    你需要获得一个数据结构来保存你的外星人 因为它只是一群外星人,所以列表可以正常工作。

    在表单中添加一个变量,以便将外星人放入。

    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, System.Generics.Collections;
    
    TForm1 = class(TForm)
    ....
    private
      Aliens: TList<TShape>;
    

    您可以在表单创建时初始化形状。 像这样的东西。

    procedure TForm1.FormCreate(Sender: TObject);
    var
      i: integer;
      AngryAlien: TShape;
    begin
      Aliens:= TList<TShape>.Create;
      for i := 0 to 100 do begin
        AngryAlien:= TShape.Create(Form1);
        AngryAlien.Parent:= Form1;
        AngryAlien.Shape:= stCircle;
        AngryAlien.Brush.Color:= clWhite;
        AngryAlien.Width:= 30;
        AngryAlien.Height:= 30;
        AngryAlien.Visible:= false;
        Aliens.Add(AngryAlien);
      end;
    end;
    

    现在你有一个 100 101外星人。

    你可以在计时器上移动外星人。

    procedure TForm1.Timer1Timer(Sender: TObject);
    var
      i: integer;
      Alien: TShape;
    begin
      //Move 4 aliens.
      for i := 0 to 100 do begin
        Alien:= Aliens[i];
        Alien.Visible:= true;
        Alien.Left:= Alien.Left + Random(30) - Random(20);
        Alien.Top:= Alien.Top + Random(15) - Random(10);
      end;
    end;
    

    现在你只需使用循环来控制每个外星人。

    如果你想要一些游戏示例代码,可以开始使用这些代码:http://delphi.about.com/od/gameprogramming/

    更具体地说:http://delphi.about.com/library/code/fdac_dodge_src.zip

    当然上面的代码是copy-paste anti pattern的一个不好的例子,我会像这样重写它:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ExtCtrls, StdCtrls;
    
    type
      TForm1 = class(TForm)
        shp_player: TShape;
        shp_enemy: TShape;
        btnStart: TButton;
        timercircle: TTimer;
        shparea: TShape;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        Label4: TLabel;
        Edit1: TEdit;
        Label5: TLabel;
        Shape1: TShape;
        Lbl_player: TLabel;
        lbl_circle: TLabel;
        lbl_enemy: TLabel;
        procedure FormCreate(Sender: TObject);
        procedure btnStartClick(Sender: TObject);
        procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
        procedure timercircleTimer(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    type
      //my own category of variables
      TLevelArray = Array [1 .. 30] of Boolean;
    
    
    var
      circle: array [1 .. 30] of TShape;
      Speedx: array [1 .. 30] of Integer;
      Speedy: array [1 .. 30] of Integer;
      Level: array [1..30] of TLevelArray;
      SpeedxCalculation: Integer;
      SpeedyCalculation: Integer;
      LevelStore: Integer = 1;
      HighScore: Boolean = False;
    
    procedure ShowCircles(Level: TLevelArray);
    var
      Count: Integer;
    begin
      for Count:= 1 to 30 do begin
        circle[Count].Visible:= Level[Count];
      end;
    end;
    
    procedure InitLevels;
    var
      i,j: integer;
    begin
      for i := 1 to 30 do begin
        FillChar(Level[i], SizeOf(Level[i]),#0);
      end;
      for i := 1 to 30 do begin
        for j := 1 to i do begin
          Level[i][j]:= true;
        end;
      end;
    end;
    
    procedure Updatecircles; //if the circle needs to be visible for that level
    var
      Count: Integer;
    begin
      for Count:= 1 to 30 do begin
        ShowCircles(Level[LevelStore]);
      end;
    end;
    
    Procedure SpeedCalculation;
    begin
      circle[LevelStore].Left:= 8; //all the circles come from the same position
      circle[LevelStore].Top:= 8;
      repeat
        Randomize; //their speeds are random for more interesting gameplay
        SpeedxCalculation:= Random(10) + 1;
        Speedx[LevelStore]:= 5 - SpeedxCalculation;
        Randomize;
        SpeedyCalculation:= Random(10) + 1;
        Speedy[LevelStore]:= 5 - SpeedyCalculation;
      until (speedy[LevelStore]) and (Speedx[LevelStore]) <> 0;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      Count: Integer;
      i: integer;
      MyCircle: TShape;
    begin
      InitLevels;
      for i := 1 to 30 do begin
        MyCircle:= TShape.Create(Self);
        MyCircle.Parent:= Self;
        MyCircle.Width:= 10;
        MyCircle.Height:= 10;
        MyCircle.Brush.Color:= clmaroon;
        MyCircle.Visible:= false;
        MyCircle[i]:= MyCircle;
      end;
      Randomize;
      shp_enemy.Left:= Random(clientwidth) - shp_enemy.width;
      shp_enemy.Top:= Random(clientheight) - shp_enemy.height;
      lbl_enemy.Left:= shp_enemy.Left;
      lbl_enemy.Top:= shp_enemy.Top - 20;
      SpeedCalculation;
      updatecircles;
    end;
    
    procedure TForm1.btnStartClick(Sender: TObject);
    begin
      TimerCircle.enabled:= True;
      btnStart.Visible:= False;
      Label2.Caption:= '0';
      Edit1.enabled:= False;
      lbl_player.Visible:= False;
      lbl_enemy.Visible:= False;
      lbl_circle.Visible:= False;
    end;
    
    procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    begin
      shp_player.Left:= x - shp_player.Width - 10;
      shp_player.Top:= y - shp_player.Height - 10; //the green block follows the mouse
      lbl_player.Left:= x - lbl_player.Width - 10;
      lbl_player.Top:= y - lbl_player.Height - 30;
    end;
    
    procedure TForm1.timercircleTimer(Sender: TObject);
    var
      overlay: Trect;
      Count: Integer;
    begin
      for Count:= 1 to LevelStore do begin
        // Moves the circles
    
        circle[Count].Left:= circle[Count].Left + speedx[Count];
        circle[Count].Top:= circle[Count].Top + speedy[Count];
    
        //bounces the circles off of the boundaries of the form
    
        if circle[Count].Left > clientwidth - circle[Count].width then speedx[Count]:= -speedx[Count]
        else if circle[Count].Left < 0 then speedx[Count]:= -speedx[Count];
    
        if circle[Count].Top > clientheight - circle[Count].Height then speedy[Count]:= -speedy[Count]
        else if circle[Count].Top < 0 then speedy[Count]:= -speedy[Count];
    
        //detects a collision between a circle and the players block
        if Intersectrect(overlay, circle[Count].BoundsRect, shp_player.BoundsRect) then begin
          c1.Left:= 8;
          c1.Top:= 8;
          btnstart.caption:= 'Restart';
          btnstart.Visible:= True;
          LevelStore:= 1;
          SpeedCalculation;
          UpdateCircles;
          timercircle.enabled:= false;
          if HighScore = True then //if a new high score has been achieved
          begin
            Edit1.Enabled:= True;
            HighScore:= False;
          end;
          lbl_player.Visible:= True;
          lbl_enemy.Visible:= True;
          lbl_circle.Visible:= True;
          lbl_enemy.Left:= shp_enemy.Left;
          lbl_enemy.Top:= shp_enemy.Top - 20;
        end;
    
        //detects a collision between the player block and target block
    
        if Intersectrect(overlay, shp_enemy.BoundsRect, shp_player.BoundsRect) then begin
          Label2.Caption:= inttostr(strtoint(Label2.Caption) + 1);
          if strtoint(Label2.Caption) > strtoint(Label4.Caption) then begin
            highscore:= True;
            Label4.Caption:= Label2.Caption;
          end;
          Randomize;
          repeat
            //the target block goes to a new position on the form
            shp_enemy.Left:= Random(clientwidth) + 2 * (shp_enemy.width);
            shp_enemy.Top:= Random(clientheight) - 2 * (shp_enemy.height);
          until ((shp_enemy.Left) > (Form1.Left + shp_enemy.Width)) and
            ((shp_enemy.Left) < (Form1.Left + clientwidth - 2 * (shp_enemy.Width))) and
            ((shp_enemy.Top) > (Form1.Top + shp_enemy.Height)) and
            ((shp_enemy.Top) < (Form1.Top + clientwidth - 2 * (shp_player.Width)));
          LevelStore:= LevelStore + 1;
          if LevelStore = 30 then // there are only 30 circles
          begin
            MessageDlg('Congratulations! - You have completed the game!', mtinformation, [mbOK], 0);
            timercircle.enabled:= false;
            btnstart.Visible:= True;
            LevelStore:= 1;
            SpeedCalculation;
            UpdateCircles;
          end else begin
            SpeedCalculation;
            UpdateCircles;
          end;
        end;
    
      end;
    end;
    
    end.//FIN - Code by Si (c)
    

    那样你don't repeat yourself