Using the Intersect method of TRect to detect Collisions

Introduction

A TRect (defined in the W3System unit) is a record with useful methods such as Create, CenterPoint, ContainsPoint, Intersect and MoveBy. In the first demo, use the mouse to move the yellow rectangle and find the hidden rectangle. The area of any overlap between the yellow and hidden rectangle will be green.

If IntersectDemo does not run in your current browser after clicking on the display, please try another (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.

Intersect Demo

The Code

See in the following code that the Intersect method of a TRect takes as parameters (1) the other TRect being tested for collision and (2) a var parameter for the TRect of the intersect region. The method returns true if there is any overlap.

unit Unit1;

interface

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

type
  TCanvasProject = class(TW3CustomGameApplication)
  private
    MobX, MobY : integer;
    StatRect : TRect;
  const
    MOB_WIDTH = 30;
    MOB_HEIGHT = 20;
  public
    procedure ApplicationStarting; override;
    procedure ApplicationClosing; override;
    procedure PaintView(Canvas: TW3Canvas); override;
  end;

implementation

procedure TCanvasProject.ApplicationStarting;
begin
  inherited;
  GameView.Width := 200;
  GameView.Height := 300;
  MobX := MOB_WIDTH div 2;
  MobY := MOB_HEIGHT div 2;
  StatRect := TRect.Create(100, 200, 130, 230);
  GameView.OnMouseMove := procedure(o : TObject; ss : TShiftState; x, y : integer)
    begin
      MobX := x;
      MobY := y;
    end;
  GameView.Delay := 1;
  GameView.StartSession(True);
end;

procedure TCanvasProject.PaintView(Canvas: TW3Canvas);
var
  MobRect, intersectRect: TRect;
begin
  // Clear background with colour teal.
  Canvas.FillStyle := 'gray';
  Canvas.FillRect(0, 0, GameView.Width, GameView.Height);
  //Draw yellow rect
  Mobrect := TRect.Create(MobX - MOB_WIDTH div 2, MobY - MOB_HEIGHT div 2, MobX + MOB_WIDTH div 2, MobY + MOB_HEIGHT div 2);
  Canvas.FillStyle := 'yellow';
  Canvas.FillRectF(MobRect); //leftX, topY, rightX, bottomY
  if mobRect.Intersect(StatRect, intersectRect) then
    begin
      Canvas.FillStyle := 'green';
      Canvas.FillRectF(intersectRect); //leftX, topY, rightX, bottomY
    end;
end;

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

end.
    

Using an array of TRect

This demonstration is the start of a maze type of game in which the player is prevented from overlapping with a wall. Use the wasd or arrow keys to navigate through the spaces between the thin rectangles. The concise code checks for a collision with each rectangle - even those with which the player has no chance of intersecting. If the response became sluggish you could choose which wall(s) to check.

If IntersectDemo2 does not run in your current browser after clicking on the display, please try another (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.

Intersect Demo

The Code

unit Unit1;

interface

uses 
  System.Types, SmartCL.System, SmartCL.Components, SmartCL.Application,
  SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics;
type
  TDirection = (Up, Down, Left, Right);
  TCanvasProject = class(TW3CustomGameApplication)
  private
    const PLAYER_SIZE = 4;
    const WALL_WIDTH = 4;
    Rects: array[1..9] of TRect;
    PlayerRect, TestRect, OverlapRect: TRect;
    MoveAttempt: Boolean;
    Direction: TDirection;
    MoveDist = 4;
    Gap, Moves: integer;
  protected
    procedure ApplicationStarting; override;
    procedure ApplicationClosing; override;
    procedure PaintView(Canvas: TW3Canvas); override;
    procedure KeyDownEvent(mCode: integer);
  end;

implementation

procedure TCanvasProject.KeyDownEvent(mCode: integer);
begin
  MoveAttempt := True;
  case mCode of
    27: Application.Terminate;
    37, 65: Direction := Left;
    38, 87: Direction := Up;
    39, 68: Direction := Right;
    40, 83: Direction := Down;
    0: MoveAttempt := False; //Initialization
  end;
end;

procedure TCanvasProject.ApplicationStarting;
begin
  inherited;
   asm
    window.onkeydown=function(e)
    {
    TCanvasProject.KeyDownEvent(Self,e.keyCode);
    }
  end;
  KeyDownEvent(0);
  Gap := 3 * PLAYER_SIZE;
  PlayerRect := TRect.Create(0, WALL_WIDTH,PLAYER_SIZE, WALL_WIDTH + PLAYER_SIZE);
  // Top, bottom, left and right boundaries
  Rects[1] := TRect.Create(0, 0, GameView.Width, WALL_WIDTH);
  Rects[2] := TRect.Create(0, GameView.Height - WALL_WIDTH,
                           GameView.Width - WALL_WIDTH - 3 * PLAYER_SIZE, GameView.Height);
  Rects[3] := TRect.Create(0, WALL_WIDTH + 3 * PLAYER_SIZE, WALL_WIDTH,
                           GameView.Height - WALL_WIDTH);
  Rects[4] := TRect.Create(GameView.Width - WALL_WIDTH, WALL_WIDTH,
                           GameView.Width, GameView.Height - WALL_WIDTH);
  //2 Horizontal walls with two gaps
  Rects[5] := TRect.Create(WALL_WIDTH, WALL_WIDTH + Gap, GameView.Width div 3, 2 * WALL_WIDTH + Gap);
  Rects[6] := TRect.Create(GameView.Width div 3 + Gap, WALL_WIDTH + Gap,
                           GameView.Width - Gap - WALL_WIDTH, 2 * WALL_WIDTH + Gap);
  Rects[7] := TRect.Create(WALL_WIDTH + Gap, 2 * (WALL_WIDTH + Gap), GameView.Width div 2,
                           3 * WALL_WIDTH + 2 * Gap);
  Rects[8] := TRect.Create(GameView.Width div 2 + Gap, 2 * (WALL_WIDTH + Gap),
                           GameView.Width - WALL_WIDTH, 3 * WALL_WIDTH + 2 * Gap);
  // Vertical wall
  Rects[9] := TRect.Create(GameView.Width div 2 - WALL_WIDTH, 2 * WALL_WIDTH + Gap,
                           GameView.Width div 2, GameView.Height - WALL_WIDTH - Gap);
  GameView.Delay := 20;
  GameView.StartSession(False);
end;

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

procedure TCanvasProject.PaintView(Canvas: TW3Canvas);
var
  Overlap: Boolean;
begin
  // Clear background
  Canvas.FillStyle := 'lightgray';
  Canvas.FillRectF(0, 0, GameView.Width, GameView.Height);
  Canvas.FillStyle := 'rgb(255, 110, 110)';
  for var r in Rects do
    Canvas.FillRectF(r);
  if MoveAttempt = True then  //Key pressed
    begin
      inc(Moves);
      TestRect := PlayerRect;
      case Direction of
        Up:    TestRect.MoveBy(0, -MoveDist);
        Left:  TestRect.MoveBy(-MoveDist, 0);
        Right: TestRect.MoveBy(MoveDist, 0);
        Down:  TestRect.MoveBy(0, MoveDist);
      end; //end of case
      Overlap := False;
      for var r in Rects do
        if TestRect.Intersect(r, OverlapRect) then
          Overlap := True;
      if not Overlap then
        PlayerRect := TestRect;  //Otherwise PlayerRect is unchanged by attempted move
    end; //end of if MoveAttempt
  Canvas.FillStyle := 'blue';
  Canvas.FillRectF(PlayerRect);
  if PlayerRect.Top > GameView.Height - WALL_WIDTH then
    begin
      ShowMessage('Moves: ' + IntToStr(Moves));
      Application.Terminate;
    end;
  MoveAttempt := False;
end;

end.
Programming - a skill for life!

Useful for games, with drawing routines (including transforms and text fonts), images, sprites and WebGL 3D graphics. Now includes Box2D physics and rendering by Pixi.js.