Using Records in Smart Pascal

A record is a composite type that allows related variables to be grouped together. In Smart Pascal, a record may also contain procedures and functions to process the data in its variables. The first example demonstrates a record with no routines.

unit Unit1;

interface

uses 
  System.Types, SmartCL.System, SmartCL.Components, SmartCL.Application,
  SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics;

type
  TCanvasProject = class(TW3CustomGameApplication)
  protected
    procedure ApplicationStarting; override;
    procedure ApplicationClosing; override;
    procedure PaintView(Canvas: TW3Canvas); override;
  end;

implementation

type
  T_Triangle = record
    Vertices: array[1..3, 1..2] of integer;
    Colour: string;
    Filled: Boolean;
  end;

var
  MyTriangle: T_Triangle;

procedure TCanvasProject.ApplicationStarting;
begin
  inherited;
  MyTriangle.Vertices := [[100, 0], [150, 100], [100, 200]];
  MyTriangle.Colour := 'red';
  MyTriangle.Filled := true;
  GameView.Delay := 20;
  GameView.StartSession(True);
end;

procedure TCanvasProject.ApplicationClosing;
begin
  GameView.EndSession;
  inherited;
end;
 
procedure TCanvasProject.PaintView(Canvas: TW3Canvas);
begin
  // Clear background
  Canvas.FillStyle := 'rgb(0, 0, 99)';
  Canvas.FillRectF(0, 0, GameView.Width, GameView.Height);
  Canvas.FillStyle := MyTriangle.Colour;
  Canvas.StrokeStyle := MyTriangle.Colour;
  // Draw triangle
  Canvas.BeginPath;
  Canvas.MoveToF(MyTriangle.Vertices[1, 1], MyTriangle.Vertices[1, 2]);
  Canvas.LineToF(MyTriangle.Vertices[2, 1], MyTriangle.Vertices[2, 2]);
  Canvas.LineToF(MyTriangle.Vertices[3, 1], MyTriangle.Vertices[3, 2]);
  Canvas.ClosePath;
  if MyTriangle.Filled = true then
    Canvas.Fill
  else
    Canvas.Stroke;
end;

end.

You receive auto-completion options from code insight when you have (1) defined your record, (2) declared a variable of that type, then (3) keyed-in the variable name followed by a period:

Code Insight

Code Insight

Select your variable with a mouse click or the vertical arrow keys and copy it to the editor with a double click or by pressing Return/Enter.

Arrays of Records

When processing multiple records of the same type you will find it convenient to put them into an array. The array of records in this example enables us to render the triangles concisely with a for-in loop.

unit Unit1;

interface

uses 
  System.Types, SmartCL.System, SmartCL.Components, SmartCL.Application,
  SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics;

type
  TCanvasProject = class(TW3CustomGameApplication)
  protected
    procedure ApplicationStarting; override;
    procedure ApplicationClosing; override;
    procedure PaintView(Canvas: TW3Canvas); override;
  end;

implementation

type
  T_Triangle = record
    Vertices: array[1..3, 1..2] of integer;
    Colour: string;
    Filled: Boolean;
  end;

var
  Triangles: array[1..3] of T_Triangle;

procedure TCanvasProject.ApplicationStarting;
begin
  inherited;
  Triangles[1].Vertices := [[100, 0], [150, 100], [100, 200]];
  Triangles[1].Colour := 'red';
  Triangles[1].Filled := true;
  Triangles[2].Vertices := [[150, 0], [200, 100], [150, 200]];
  Triangles[2].Colour := 'green';
  Triangles[2].Filled := false;
  Triangles[3].Vertices := [[200, 0], [250, 100], [200, 200]];
  Triangles[3].Colour := 'yellow';
  Triangles[3].Filled := true;
  GameView.Delay := 20;
  GameView.StartSession(True);
end;

procedure TCanvasProject.ApplicationClosing;
begin
  GameView.EndSession;
  inherited;
end;
 
procedure TCanvasProject.PaintView(Canvas: TW3Canvas);
begin
  // Clear background
  Canvas.FillStyle := 'rgb(0, 0, 99)';
  Canvas.FillRectF(0, 0, GameView.Width, GameView.Height);
  // Draw triangles
  for  var Triangle in Triangles do
    begin
      Canvas.FillStyle := Triangle.Colour;
      Canvas.StrokeStyle := Triangle.Colour;
      Canvas.BeginPath;
      Canvas.MoveToF(Triangle.Vertices[1, 1], Triangle.Vertices[1, 2]);
      Canvas.LineToF(Triangle.Vertices[2, 1], Triangle.Vertices[2, 2]);
      Canvas.LineToF(Triangle.Vertices[3, 1], Triangle.Vertices[3, 2]);
      Canvas.ClosePath;
      if Triangle.Filled = true then
        Canvas.Fill
      else
        Canvas.Stroke;
    end;
end;

end.

The Inbuilt TRect Record

The next example uses the Create, CreateSized, MoveBy and Intersect routines of the inbuilt TRect record (in the System.Types unit). The mobile moves diagonally until any further movement would make it intersect with the obstacle. Use of the inbuilt record with its well-named routines makes the code tight and easy to follow.

unit Unit1;

interface

uses 
  System.Types, SmartCL.System, SmartCL.Components, SmartCL.Application,
  SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics;

type
  TCanvasProject = class(TW3CustomGameApplication)
  protected
    procedure ApplicationStarting; override;
    procedure ApplicationClosing; override;
    procedure PaintView(Canvas: TW3Canvas); override;
  end;

implementation

var
  Mob, Obstacle, Intersection: TRect;

procedure TCanvasProject.ApplicationStarting;
begin
  inherited;
  Mob := TRect.Create(0, 0, 20, 10);
  Obstacle := TRect.CreateSized(200, 200, 20, 20);
  GameView.Delay := 20;
  GameView.StartSession(True);
end;

procedure TCanvasProject.ApplicationClosing;
begin
  GameView.EndSession;
  inherited;
end;

procedure TCanvasProject.PaintView(Canvas: TW3Canvas);
begin
  // Clear background
  Canvas.FillStyle := 'rgb(0, 0, 99)';
  Canvas.FillRectF(0, 0, GameView.Width, GameView.Height);
  // Draw obstacle and mobile
  Canvas.FillStyle := 'black';
  Canvas.FillRect(Obstacle);
  Canvas.FillStyle := 'red';
  Canvas.FillRect(Mob);
  Mob.MoveBy(1, 1);
  if Mob.Intersect(Obstacle, Intersection) then
    Mob.MoveBy(-1, -1);
end;

end.

Other Inbuilt Records

If you need rectangles with greater precision you can use the TRectF record. Other types in the System.Types unit that you may find useful in your games include TPoint, TPointArray, TPointF and TPointArrayF. The Distance and AngleTo functions of TPoint made this demonstration easy to write. The code follows the application in action. You should see a yellow line from the centre of a blue frame to the pointer as you move the mouse and read the angle and distance of the pointer from the centre. If the application does not work, please use another browser such as Chrome. If you see no display at school, the security system might have blocked it. You can try instead this direct link to the program running on its own page.

TPointDemo
unit Unit1;

interface

uses
  System.Types, SmartCL.System, SmartCL.Components, SmartCL.Application,
  SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics;

type
  TCanvasProject = class(TW3CustomGameApplication)
  protected
    procedure ApplicationStarting; override;
    procedure ApplicationClosing; override;
    procedure PaintView(Canvas: TW3Canvas); override;
  end;

implementation

var
  Centre, MousePos: TPoint;
  Angle, Distance: real;

procedure TCanvasProject.ApplicationStarting;
begin
  inherited;
  GameView.OnMouseMove := procedure(o : TObject; ss : TShiftState; x, y : integer)
    begin
      MousePos.X := x;
      MousePos.Y := y;
    end;
  Centre.X := GameView.Width div 2;
  Centre.Y := GameView.Height div 2;
  GameView.Delay := 1;
  GameView.StartSession(false);
end;

procedure TCanvasProject.ApplicationClosing;
begin
  GameView.EndSession;
  inherited;
end;

procedure TCanvasProject.PaintView(Canvas: TW3Canvas);
begin
  // Clear background
  Canvas.FillStyle := 'rgb(0, 0, 99)';
  Canvas.FillRectF(0, 0, GameView.Width, GameView.Height);
  // Find distance and angle
  Distance := Centre.Distance(MousePos);
  Angle := Centre.AngleTo(MousePos) * 180 / Pi;
  // Draw line from centre to pointer
  Canvas.StrokeStyle := 'yellow';
  Canvas.BeginPath;
  Canvas.LineF(Centre.X, Centre.Y, MousePos.X, MousePos.Y);
  Canvas.Stroke;
  // Draw angle and distance on top left of screen
  Canvas.Font := '10pt verdana';
  Canvas.FillStyle := 'rgb(255, 255, 255)';
  Canvas.FillTextF('Angle: ' + IntToStr(Round(Angle)) + ' Distance: ' + IntToStr(Round(Distance)), 10, 20, MAX_INT);
end;

end.
Programming - a skill for life!

How to learn the Smart Pascal language the fun way by making games. Use Blockly blocks at first if coming from Scratch.