Habe Probleme mit Timer-Events (besonders auf modernen PCs)
14. Mär 2007, 21:21
Liebe Leute,
ich hab ein ganz schön aufwendiges Spiel programmiert (500 Stunden). Nicht mein erstes. Ich habe inzwischen auch schon sehr vieles dazugelernt. Es sei erwähnt, daß ich eine bestimme Anzahl an Frames pro Sekunde zeichnen will/muß.
Meine Frage lautet eigentlich: Wie programmiert man so eine die Zeitsteuerung richtig?
In diesem Fall will ich exakt 25 FPS.
Beschreibung meines ersten Versuches
Zuerst habe ich die TTimer Komponente verwendet: Sie ruft HandleFrame() auf, die alle Änderungen berechnet und eine Grafik auf den TForm.Canvas ausgibt. Auf meinem 866 MHz PC mit WinXP SP2 läuft es sehr fein. Aber auf einem 1.8 GHz mit XP, mit & ohne SP, mit und ohne Windows-Updates und auf einem 3 GHz PC eines Freundes bekomm ich genau 22 FPS. Ich habe an verschiedenen Stellen der Funktion HandleFrame() mittels GetTickCount Debugmeldungen eingebaut (um die Performance einzelner Progammteile zu checken). Auf meinem 866er bekomm ich von GetTickCount Vielfache von 10, auf den schnellen PCs Vielfache von 8.
FRAGE 1: Mir ist der genaue Grund nicht klar, warum auf den modernen PCs die Timerauflösung anders ist, laut WWW soll sie unter 95/98/ME etwa 55ms/Tick sein, XP/2K 10ms und NT 3.x 16ms, auf allen Rechnern lief aber XP. Ich vermute, es liegt an der Hardware? Hier hätte ich gern ein bisserl Aufklärung.
Beschreibung meines zweiten Versuches
Danach habe ich eine PseudoTimer() Funktion mit Repeat/Application.ProcessMessages geschrieben, ebenfalls mit GetTickCount, und keinen Unterschied erreicht. Das seh ich auch ein.
FRAGE 2: Ich hätte gern eine Möglichkeit die Zeit mit höherer Genauigkeit zu bekommen, das würde mir auch bei anderen Programmen helfen, und ich könnte mein Spiel sofort mit der PseudoTimer funktion rauslassen.
Meines dritter Versuch
Dann habe ich einen MultimediaTimer verwendet mittels Callbackfunktion, und zwar so:
FID := timeSetEvent( 1000 div DESIRED_FPS, 0, @timeCallBack, 0, TIME_PERIODIC );
Das funktioniert soweit ganz gut, was die Framerate angeht, allerdings habe ich zwei Probleme damit:
Auf zu langsamen Rechnern überholt sich die Callbackfunktion selbst, angeblich wird ja diese Callbackfunktion von einem eigenen Thread aus aufgerufen. Das führte zu Hackern in der Musik (bass.dll) wenn man eine Taste drückt, und zu Unterschieden in der Random() Reihe (!?). Eine globale Variable "FrameCurrentlyBeingCalculated", die der Callback verbietet, HandleFrame() aufzurufen, hat seltsamerweise nichts gebracht.
Zweitens verliert die Hauptform ständig/permanent den Eingabefokus, wenn ich den Multimediatimer verwende, weshalb ich die "automatische-Pause-onLooseFocus" deaktivieren müßte. Ich könnte die HandleFrame() Routine ja nicht in der Callbackfunktion aufrufen, sondern ein Signal an das Hauptform senden. Aber:
FRAGE 3: Warum läuft TTimer scheinbar nicht in einem anderen Thread??
Ich wünsch mir eigentlich nur einen TTimer, der auf allen Rechnern in der Lage ist 25x pro Sekunde zu triggern. Vielleicht gibts da ja etwas. Ich mag es nämlich nicht gerne, wenn ich durch solche Probleme meinen hübschen schlichten und leicht lesbaren Delphi-Code mit kryptischen Systemaufrufen, Workarounds und anderen schmutzigen Hacks verunstalten muß. Ich hab schon tagelang im Netz gesucht, und hoffe hier endlich Hilfe zu finden.
Liebe Grüße!
|