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 |
|---|---|---|
|
When you construct the screen, before VGA is up |
Plain field initialization |
|
Once for every screen, after VGA is up, before loop |
Set the palette, prepare buffers |
|
Each time the screen becomes active |
Reset state, start music, draw |
|
Every frame while active |
Input, logic, rendering |
|
Each time the screen becomes inactive |
Pause timers, save state |
|
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:
The old screen’s
HiderunsThe active screen changes
The new screen’s
Showruns
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
Gameinstance, which is why they take no constructor parameters.The game frees all registered screens in
Done; do not dispose them yourself.DeltaTimeis in seconds, so multiply speeds by it to stay frame-rate independent.
See Also
TBaseGame — the game object that owns and switches screens
Dirty Rectangles — partial screen updates
Engine Internals — where the lifecycle calls come from