Title: Real time movement in games
Question: Why waste processing time while waiting for a delay to have passed. Move your sprite as much as possible for smoother animation.
Answer:
In this example I'm moving the application icon from left to right with a certain speed (300 pixels per second), WITHOUT a timer. I only use a loop, and check with each loop how much time has passed and thus how much I should move.
To get the time, I use GetTickCount, which should return the number of milli seconds since booting.
The following code will show that it doesn't change every milli second.
var s: cardinal
begin
s := GetTickCount;
repeat
Memo1.Lines.Add( IntToStr( GetTickCount ) );
until s end;
If you look at the result in the memo, you'll see that it produces times the same number, and then suddenly increases with 10 instead of 1. (This may vary on other configurations.) So unfortunately we won't reach a frame rate higher than 100.. Good enough for me. :-)
Back to the sample.
I chose a speed of 300 Pixels per second, and I determined how many pixels I should move in one tick (one milli second).
In a loop (the Game Main loop) I calculate how much ticks have passed, and multiply this with PixelsPerTick value. Now I know how much to move.
Place the code below in a buttons OnClick event, and see what happens.
procedure TForm1.Button1Click(Sender: TObject);
const PIXELSPERSECOND = 300;
var
x : single;
PixelsPerTick: single;
StartTick, OldTick, CurTick, TickDif: Cardinal;
Frames: integer;
begin
PixelsPerTick := (PIXELSPERSECOND / 1000);
Refresh; // Clear previous drawing
Frames := 0;
x := 0; // Set initial position
StartTick := GetTickCount;
CurTick := StartTick;
repeat
Application.ProcessMessages; // Make application react to (user) input
OldTick := CurTick; // Time at last frame
CurTick := GetTickCount; // Current time
TickDif := CurTick - OldTick; // Time delta
if TickDif 0 then // At least 1 milli second has passed since last frame
begin
inc( Frames ); // Just a counter for statistics
x := x + (PixelsPerTick * TickDif); // move sprite
Canvas.Draw( Round(x), 15, Application.Icon ); // Draw sprite
end;
until x (Width - 32); // We've moved across the window?
// Show some statistics
ShowMessage( Format ( '%d frames in %f seconds. Moved %d pixels. %f frames per second', [Frames, (CurTick-StartTick)/1000, Round( x ), (Frames/((CurTick-StartTick)/1000)) ] ) );
end;