Screens (TScreen)

Unit: Screen

A screen is one state of your game — the title screen, the gameplay screen, the settings menu. TScreen is the base object you extend; this is where most of your game code actually lives.

The game object holds a map of named screens and calls the lifecycle methods of whichever one is active.

Lifecycle

Method

When it runs

Typical use

Init

When you construct the screen, before VGA is up

Plain field initialization

PostInit

Once for every screen, after VGA is up, before loop

Set the palette, prepare buffers

Show

Each time the screen becomes active

Reset state, start music, draw

Update

Every frame while active

Input, logic, rendering

Hide

Each time the screen becomes inactive

Pause timers, save state

Done

When the game shuts down

Free what the screen allocated

The split between Init and PostInit is the one to remember: screens are constructed before the display mode is set, so anything that touches VGA — the palette above all — belongs in PostInit, not Init.

Show and Hide can run many times as the player moves between screens; PostInit and Done run exactly once.

A minimal screen

unit TitleScr;

interface

uses
  VGA, Screen, Keyboard, MyGameUnit;

type
  PTitleScreen = ^TTitleScreen;
  TTitleScreen = object(TScreen)
    Elapsed: Real;
    constructor Init;
    procedure PostInit; virtual;
    procedure Show; virtual;
    procedure Update(DeltaTime: Real); virtual;
  end;

implementation

constructor TTitleScreen.Init;
begin
  inherited Init;
  Elapsed := 0.0;
end;

procedure TTitleScreen.PostInit;
begin
  inherited PostInit;

  { VGA is up - safe to touch the palette }
  SetPalette(Game.Palette^);
end;

procedure TTitleScreen.Show;
begin
  { Draw the static background once, then copy it in each frame }
  PutImage(Game.TitleImage^, 0, 0, False, Game.BackgroundBuffer);
  CopyFrameBuffer(Game.BackgroundBuffer, Game.BackBuffer);
  RenderFrameBuffer(Game.BackBuffer);
  Elapsed := 0.0;
end;

procedure TTitleScreen.Update(DeltaTime: Real);
begin
  Elapsed := Elapsed + DeltaTime;

  if IsKeyPressed(Key_Enter) then
    Game.SetNextScreen('game');

  if IsKeyPressed(Key_Escape) then
    Game.Stop;
end;

end.

Register it from your main program:

New(TitleScreen, Init);
Game.AddScreen('title', TitleScreen);
Game.SetNextScreen('title');

Switching screens

Call Game.SetNextScreen('name'). The switch is deferred — it happens at the start of the next frame, never in the middle of one:

  1. The old screen’s Hide runs

  2. The active screen changes

  3. The new screen’s Show runs

So it is safe to switch from inside Update, including from a click handler, without worrying about the rest of the frame running against a half-swapped state.

Rendering

Screens render themselves — the framework does not draw anything for you. In Update, draw into Game.BackBuffer and then push it to the display with RenderFrameBuffer, or with FlushDirtyRects if you are only updating parts of the screen.

The common pattern is to draw the static parts once into Game.BackgroundBuffer in Show, then each frame restore the areas that changed from it before drawing the moving objects on top. See dirty rectangles.

Notes

  • Every method is virtual — override only the ones you need.

  • Screens reach shared state through the global Game instance, which is why they take no constructor parameters.

  • The game frees all registered screens in Done; do not dispose them yourself.

  • DeltaTime is in seconds, so multiply speeds by it to stay frame-rate independent.

See Also