Question

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.

Was it helpful?

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.

OTHER TIPS

Create your objects dynamically at runtime and keep track of them in a list, then you can loop through the list when needed, eg:

unit Unit1; 

interface 

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

type 
  TForm1 = class(TForm) 
    PanelTimer: TTimer; 
    Button1: TButton; 
    LazerTimer: TTimer; 
    Image1: TImage; 
    procedure PanelTimerTimer(Sender: TObject); 
    procedure Button1Click(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(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 LazerTimerTimer(Sender: TObject); 
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton; 
      Shift: TShiftState; X, Y: Integer); 
  private 
    { Private declarations } 
    Lazers: TList; 
    Panels: TList; 
    procedure StartPanelAnimation;
    procedure StartLazerAnimation; 
  public
    { Public declarations } 
  end; 

var 
  Form1: TForm1; 

implementation 

{$R *.dfm} 

{ TForm1 } 

procedure TForm1.StartPanelAnimation; 
var
  Panel: TPanel;
begin 
  Panel := TPanel.Create(Self);
  Panel.Parent := Self;
  Panel.Top := 0;
  // set other Panel properties as needed... 
  Panel.Visible := True; 
  Panels.Add(Panel);
  if not PanelTimer.Enabled then
  begin
    PanelTimer.Interval := 1; 
    PanelTimer.Enabled := True; 
  end;
end; 

procedure TForm1.PanelTimerTimer(Sender: TObject); 
var
  k: Integer;
  Panel: TPanel;
begin 
  for k := 0 to Panels.Count-1 do
  begin
    Panel := TPanel(Panels[k]);
    Panel.Top := Panel.Top + 1; 
    if Panel.Top = 512 then 
      Panel.Top := 0;
  end;
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
  StartPanelAnimation1;  
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
  Lazers := TList.Create;
  Panels := TList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
  Lazers.Free;
  Panels.Free;
end;

procedure TForm1.FormActivate(Sender: TObject); 
begin 
  PanelTimer.Enabled := False; 
  LazerTimer.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.StartLazerAnimation; 
var
  Lazer: TShape;
begin 
  Lazer := TShape.Create(Self);
  Lazer.Parent := Self;
  // set Lazer properties as needed...
  Lazer.Top := Image1.Top; 
  Lazer.Left := Image1.Left + 55; 
  Lazer.Visible := True; 
  Lazers.Add(Lazer);
  if not Lazer.Enabled then
  begin
    Lazer.Interval := 1; 
    Lazer.Enabled := True; 
  end;
end; 

procedure TForm1.LazerTimerTimer(Sender: TObject); 
var
  k, m : integer;
  Lazer: TShape;
  Panel: TPanel;
  PanelHit: Boolean; 
begin 
  k := 0;
  while k < Lazers.Count do
  begin
    Lazer := TShape(Lazers[k]);
    Lazer.Top := Lazer.Top - 10; 
    for m := 0 to Panels.Count-1 do
    begin        
      Panel := TPanel(Panels[m]);
      PanelHit := (Lazer.Top > (Panel.Top+Panel.Height)) and (Lazer.Left > Panel.Left) and (Lazer.Left < (Panel.Left+Panel.Width));
      if PanelHit then
      begin
        Panels.Remove(Panel);
        Panel.Free;
        if Panels.Count = 0 then
          PanelTimer.Enabled := False;
        Break;
      end;
    end;
    if PanelHit or (Lazer.Top = 0) then 
    begin 
      Lazers.Remove(Lazer);
      Lazer.Free;
      if Lazers.Count = 0 then
        LazerTimer.Enabled := False; 
    end else
      Inc(k); 
  end;
end; 

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

end.  
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top