PDA

View Full Version : TTimer



Delphi Kid
30-04-2004, 07:49 PM
Hi, I made a realtime game on a timer with interval 10ms.

I tested this game on the same computer but on 3 different OS.

Windows XP pro - 10ms 100%
Windows XP home - 15,5ms 64%
Windows 98 - 50ms 20%

WTF!!. This is weird. Obviously there is some setting in the OS that manipulate the Timer.

Also gettickcount seems to work on those rates, I used a ping method with gettickcount and on 98 I get only pings of 0-50-100-etc

Does anyone know how I can change those settings?

thx in advance

noeska
30-04-2004, 08:31 PM
I am using the threaded timer from http://www.carlosb.com now. This solved the timing problem with my openal modplayer.

TheLion
01-05-2004, 06:16 PM
NEVER EVER use TTimer object for a game! ;) hehe
It's really the most unreliable timer object I know! ;)

GetTickCount is quite accurate, however you can set the accuracy/resolution for this timer, which will also make it run sync on each system...


// Initialization
DWORD TickResolution;
TIMECAPS TimeCaps;
if (timeGetDevCaps(&TimeCaps, sizeof(TIMECAPS)) == TIMERR_NOERROR)
{
TickResolution = min(max(TimeCaps.wPeriodMin, 1U), TimeCaps.wPeriodMax);
timeBeginPeriod(TickResolution);
}

... // All game stuff

// Cleanup
timeEndPeriod(TickResolution);

(and yes the code above is C++, taken from here:
http://www.intheoryforum.com/viewtopic.php?t=43&start=0&postdays=0&postorder=asc&highlight=)

Delphi Kid
02-05-2004, 11:42 AM
Thanks lion. But can you convert that to delphi for me? or assembler?

TheLion
02-05-2004, 01:37 PM
Well... because you asked so nicely! ;)


var Form1: TForm1;
TickResolution : DWORD;
TimeCaps : TTIMECAPS;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
Begin
If ( TimeGetDevCaps(@TimeCaps, sizeof(TIMECAPS)) = TIMERR_NOERROR ) Then
Begin
// 1 ms = Accuracy, change the 1 in Max(TimeCaps.wPeriodMin, 1) for a different accuracy! :)
TickResolution := Min( Max(TimeCaps.wPeriodMin, 1), TimeCaps.wPeriodMax);
TimeBeginPeriod(TickResolution);
End;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// Cleanup
TimeEndPeriod(TickResolution);
End;


NOTE: You'll have to include the MMSystem and the Math unit in your application, however you could leave out the math unit and write your own Min/Max function! ;) This example sets the accuracy of the timer to 1 ms, but you could set the accuracy to whatever you want! :)

Delphi Kid
02-05-2004, 11:59 PM
Thanks for your effort! but ....

Well I added the code, unfortunately it is still skipping ~15 ms on my Win XP. I added a button that checks the gettickcount until 50ms passed. and gettickcount ends with 63 instead of 50.

Maybe I am doing something wrong :/



unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, MMSystem , math, StdCtrls, ExtCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
end;

var
Form1: TForm1;
TickResolution : DWORD;
TimeCaps : TTIMECAPS;
i,number:integer;

implementation

{$R *.dfm}

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
TimeEndPeriod(TickResolution);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
If ( TimeGetDevCaps(@TimeCaps, sizeof(TIMECAPS)) = TIMERR_NOERROR ) Then
Begin

TickResolution := Min( Max(TimeCaps.wPeriodMin, 1), TimeCaps.wPeriodMax);
TimeBeginPeriod(TickResolution);
End;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
i:=gettickcount;
while i+50 > gettickcount do begin
number:=gettickcount-i;
end;
showmessage(inttostr(number));
end;

end.



edit: btw the comparison in oncreate procedure does return TIMERR_NOERROR, so thats not the problem

Useless Hacker
03-05-2004, 10:02 AM
You should be using timeGetTime (declared in MMSystem.pas) instead of GetTickCount.

noeska
04-05-2004, 05:28 PM
Try using the threaded timer component. It should do the trick.

TheLion
05-05-2004, 08:53 AM
Well in you ask the GetTickCount twice when calculating with it, so it allready passed the 50 when you calculate with it, however I didn't claim GetTickCount would be accurate! ;)


i:=gettickcount;
while i+50 > gettickcount do begin
// Here you ask the new GetTickCount, which is allready higher than the one in the while function...
number:=gettickcount-i;
end;
showmessage(inttostr(number));
end;

GetTickCount, will never be accurate, but you didn't ask for an accurate timer, you asked for a timer that would work approx. the same on all machines, don't forget you are using a loop and a few statements, all those things take time. But what do you need it for? If you want to make a sprite move timed over the screen then there is no need for perfect accuracy! :)

If you want a faster more accurate timer use the timeGetTime function Useless Hacker suggested or you could write or use a third-party threaded-timer, however most threaded-timers I've seen use GetTickCount or timeGetTime in combination with a sleep internally! :)