Using a Timer

In our Lazarus demonstration we show you how to use a Timer to repeat a sequence of commands after a set interval. The Enabled property is True so that the motion starts immediately. We set the interval property to 40. The sequence of three lines of code within the Timer1Timer procedure is executed repeatedly but each sequence is separated from the next by an interval of 40 milliseconds. The user can change the interval at runtime using the scrollbar. The ball bounces off each wall and you position the bat using the trackbar so that it will hit the bat. Each time you record a hit, the distance moved by the ball increments. This game might engage you for a minute or two, but you will no doubt quickly think up and develop your own games based on timers.

The screenshot shows a game of "Solo Pong".

Output from program TimerDemo

Output from program TimerDemo

Our code of the files needed for program TimerDemo follows. You can copy the code if necessary, but a you should be able to adapt it for your own use of a timer by looking at the code.

uTimerDemo.pas

unit uTimerDemo;

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  ComCtrls, StdCtrls;

type
  TfrmSoloPong = class(TForm)
    lblHits: TLabel;
    lblMisses: TLabel;
    Panel1: TPanel;
    ScrollBar1: TScrollBar;
    shpBall: TShape;
    shpBat: TShape;
    StaticText1: TStaticText;
    Timer1: TTimer;
    TrackBar1: TTrackBar;
    procedure ScrollBar1Change(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  end; 

var
  frmSoloPong: TfrmSoloPong;

implementation

{$R *.lfm}

const
  UPPER_LIMIT = 0;
  LEFT_LIMIT = 0;
  LOWER_LIMIT = 200;
  RIGHT_LIMIT = 200;

var
  BallMoveDist: integer = 5;
  RightNext, DownNext : Boolean;
  Hits, Misses : integer;

procedure BallMove;
var
  BallLeft, BallTop : integer;
begin
  with frmSoloPong do
    begin
      if (shpBall.Left + shpBall.Width) >= RIGHT_LIMIT then
        RightNext := False;
      if shpBall.Left <= LEFT_LIMIT then
        RightNext:= True;
      if (shpBall.Top + shpBall.Height) >= LOWER_LIMIT then
        DownNext := False;
      if shpBall.Top <= UPPER_LIMIT then
        DownNext:= True;

      if RightNext then
        begin
          BallLeft:= shpBall.Left + BallMoveDist;
          if BallLeft > (RIGHT_LIMIT - shpBall.Width) then
            BallLeft := RIGHT_LIMIT - shpBall.Width;
        end
      else
        begin
          BallLeft:= shpBall.Left - BallMoveDist;
          if BallLeft < LEFT_LIMIT then
            BallLeft := LEFT_LIMIT;
        end;
      if DownNext then
        begin
          BallTop := shpBall.Top + BallMoveDist;
          if BallTop > (LOWER_LIMIT - shpBall.Height) then
            BallTop := LOWER_LIMIT - shpBall.Height;
        end
      else
        begin
          BallTop := shpBall.Top - BallMoveDist;
          if BallTop < UPPER_LIMIT then
            BallTop := UPPER_LIMIT;
        end;
      shpBall.SetBounds(BallLeft, BallTop, shpBall.Width, shpBall.Height);
    end;
end;

procedure HitOrMiss;
begin
  with frmSoloPong do
    begin
      if (shpBall.Left < BallMoveDist) and not RightNext then
        begin  //ball moving towards left edge
          //if ball above or below the bat
          if (shpBall.Top + (shpBall.width div 2) < shpBat.Top) or
             (shpBall.Top - (shpBall.width div 2) > (shpBat.Top + shpBat.Height)) then
            begin
              inc(Misses);
              lblMisses.Caption := 'Misses: ' + intToStr(Misses);
            end
          else // a hit
            begin
              inc(Hits);
              lblHits.Caption := 'Hits: ' + intToStr(Hits);
              //Increase distance moved so that path changes
              BallMoveDist :=  BallMoveDist + 1;
            end;
        end;
    end;
end;

procedure TfrmSoloPong.Timer1Timer(Sender: TObject);
begin
  BallMove;
  shpBat.Top := Trackbar1.Position - (shpBat.Height div 2);
  HitOrMiss;
end;

procedure TfrmSoloPong.ScrollBar1Change(Sender: TObject);
begin
  Timer1.Interval := Scrollbar1.Position;
end;

end.

uTimerDemo.lfm

object frmSoloPong: TfrmSoloPong
  Left = 521
  Height = 274
  Top = 279
  Width = 269
  Caption = 'Solo Pong'
  ClientHeight = 274
  ClientWidth = 269
  LCLVersion = '0.9.30'
  object Panel1: TPanel
    Left = 32
    Height = 200
    Top = 24
    Width = 200
    ClientHeight = 200
    ClientWidth = 200
    Color = 11533559
    ParentColor = False
    TabOrder = 0
    object shpBall: TShape
      Left = 0
      Height = 10
      Top = 40
      Width = 10
      Brush.Color = clGreen
      Pen.Color = clGreen
      Shape = stCircle
    end
    object shpBat: TShape
      Left = 0
      Height = 20
      Top = 90
      Width = 1
      Brush.Color = clMaroon
      Pen.Color = clMaroon
    end
  end
  object TrackBar1: TTrackBar
    Left = 3
    Height = 200
    Top = 24
    Width = 25
    Max = 200
    Orientation = trVertical
    Position = 100
    ShowSelRange = False
    TickStyle = tsNone
    TabOrder = 1
  end
  object lblHits: TLabel
    Left = 28
    Height = 21
    Top = 232
    Width = 34
    Caption = 'Hits: '
    ParentColor = False
  end
  object lblMisses: TLabel
    Left = 96
    Height = 21
    Top = 232
    Width = 51
    Caption = 'Misses: '
    ParentColor = False
  end
  object ScrollBar1: TScrollBar
    Left = 240
    Height = 121
    Top = 152
    Width = 21
    Kind = sbVertical
    LargeChange = 5
    Max = 60
    Min = 10
    PageSize = 0
    Position = 40
    TabOrder = 2
    OnChange = ScrollBar1Change
  end
  object StaticText1: TStaticText
    Left = 194
    Height = 17
    Top = 232
    Width = 48
    Caption = 'Speed'
    TabOrder = 3
  end
  object Timer1: TTimer
    Interval = 40
    OnTimer = Timer1Timer
    left = 248
    top = 32
  end
end

TimerDemo.lpr

program TimerDemo;

uses
  Interfaces, Forms, uTimerDemo;

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TfrmSoloPong, frmSoloPong);
  Application.Run;
end.

Nathan Horsley's Shoot game makes effective use of timers.

Programming - a skill for life!

Using widgets (such as list boxes, combo boxes, string grids, DBgrids, charts and maps) and drawing on the canvas