Search code examples
delphidelphi-7duplication

How to add more objects to my form without adding the same amount of code


I have been making a small game for fun. In the game you are a small spaceship(an image) that shoots lazer beams(shape) at an object(panel). At this moment u can only fire one lazer beam at a time because there is only one lazer beam(shape) and there is only one object(panel) to shoot. So with the coding I have I would like to know how I can add more lazer beams and objects but especially lazer beams because I don't want to repeat the procedures for each lazer beam and for each panel.

Here is the code.

unit Unit1;

interface

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

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 }
  public
   procedure StartPanelAnimation1;
   procedure DoPanelAnimationStep1;
   function  PanelAnimationComplete1: Boolean;
   procedure Startlazeranimation1;
   procedure DolazeranimationStep1;
   { 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;
 timer3.Enabled := 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.DolazeranimationStep1;
begin
 shape1.Top := shape1.Top-10;
end;


 procedure TForm1.Startlazeranimation1;
 begin
 shape1.Top := image1.Top;
 shape1.Left := image1.Left+55;
 shape1.Visible := true;
  Timer3.Interval := 1;
  Timer3.Enabled := True;
end;

procedure TForm1.Timer3Timer(Sender: TObject);
var k : integer;
begin
 DolazeranimationStep1;
  if (shape1.Top < panel1.Top) and (shape1.Left < panel1.Left+104) and (shape1.Left > panel1.Left) or         (shape1.Top=clientheight) then
   begin
    timer3.Enabled := false;
    shape1.Visible := false;
    for k := 1 to 5 do
    sleep(1);
    begin
    application.ProcessMessages;
    end;
    shape1.Top := 0;
    shape1.Left := 0;
   end;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 shape1.Show;
 startlazeranimation1;
end;

end.

(The above is the old code)

I have successfully done what Stijn Sanders suggested. But now in this if

 if (Shape1.top < panel1.Top) and (shape1.Left < panel1.Left+104) and (shape1.Left > panel1.Left)   then

never tests true because shape1 never passes panel1 it, only the shape created on on click passes the panel.

So is there another way to test if the shape is at the pnael.


Solution

  • Not all components need to be created at design time. At run-time, for example using a TTimer and its event, you can call TShape.Create(Self); to have an extra shape. Keep the reference to the resulting value somewhere convenient, for example a (dynamic) array, and remember to set MyShape.Parent:=Self; or MyShape.Parent:=Panel1; so the system knows when and where to display this new control.

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ExtCtrls;
    
    const
      MaxRays=100;
      RayStep=8;
    
    type
      TForm1 = class(TForm)
        Timer1: TTimer;
        procedure FormCreate(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
        procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
      private
        { Private declarations }
        Rays:array[0..MaxRays-1] of TShape;
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      i:integer;
    begin
      for i:=0 to MaxRays-1 do Rays[i]:=nil;
    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.Timer1Timer(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;
    
    end.