Timer zu langsam
-
NES-Spieler schrieb:
Wenn Ihr ein Männchen von links nach rechts bewegen wolltet, wie würdet Ihr das mit der Zeit zwischen zwei Schritten realisieren?
Pass die Schrittweite der Zeit an, nicht umgekehrt.
Wie ich vorher schon mal geschrieben habe: Mach das, was zwischen zwei Frames zu tun ist, miss nach, wie lange das gedauert hat, und bewege dann das Männchen um eine Strecke, die dieser Zeit entspricht. Pausen bringen dich nicht überhaupt nicht weiter. Mit Pausen bekommst du nur dann eine halbwegs konstante Geschwindigkeit hin, wenn du auf einen Großteil der Prozessorleistung verzichtest. Wenn du auf unterschiedlich schnellen Systemen trotzdem ähnliche Geschwindigkeiten erzielen willst, geht es mit Pausen gar nicht.
Bitte erklärt mir jetzt nicht, daß man mit der MFC keine Spiele programmiert!
Jedenfalls benutzt man die Windows-Messagequeues nicht für die Steuerung von zeitlichen Abläufen oder Ein-/Ausgabe. Weder mit MFC noch ohne.
-
Du könntest dir mal ein Buch holen in dem steht wie man es richtig macht!
-
Ich meine mal irgendwo (ist schon lange her, wahrscheinlich noch Win 3.1) gelesen zu haben, dass sich der Windows-Timer über die Netzfrequenz (50 Hz) seine Zeit holt. Damit wäre der kleinste mögliche Abstand 20ms bzw. Vielfache davon.
-
AndRo67 schrieb:
Ich meine mal irgendwo (ist schon lange her, wahrscheinlich noch Win 3.1) gelesen zu haben, dass sich der Windows-Timer über die Netzfrequenz (50 Hz) seine Zeit holt.
Das ist kompletter Unsinn. Als ich zuletzt nachgeschaut habe, hatte mein PC ein Netzteil, das Gleichspannung erzeugt. Nix mit Frequenz.
-
LOl dann hast ne Frequenz von 0
dann sollte es doch ein geiler Timer sein!
*ROFL*
-
Brauchst du denn unbedingt eine Genauigkeit von 1ms??? Nimm doch einfach höhere Werte, dann ist der Timer auch ziemlich genau. Hab grad z.B. grad das hier mit einem Timerintervall von 50ms getestet:
[cpp]void CMainFrame::OnTimerTest() { m_nSekunden = 0; m_StartZeit = clock(); SetTimer(1,50,NULL); } void CMainFrame::OnTimer(UINT nIDEvent) { m_nSekunden++; if(m_nSekunden == 400) { int Zeit = clock() - m_StartZeit; TRACE("Reale Zeit: %ims\n",Zeit); MessageBox("20 Sekunden!"); KillTimer(1); } CFrameWnd::OnTimer(nIDEvent); }[/cpp]
Als Ergebnis hab ich 20029ms erhalten, damit kann man doch leben, oder?
(Und ich habe keinen HighEnd-Rechner!
) Also, falls du keine andere Lösung findest, musst du wohl dein Timerintervall erhöhen. Und 50ms müssten doch als Intervall für ein (einfaches) Spiel reichen.
Übrigens: Hab grad noch n bisschen weitergetestet, für Werte über 50ms ändert sich die Genaugigkeit nicht mehr, bei 100ms und dann logischerweise m_nSekunden==200 erhalte ich als reale Zeit ebenfalls 20029ms. Bei 25ms gibts allerdings schon 24075ms für 20sek. Also stimmt anscheinend die Aussage, dass man Timer nur über 50ms benutzen sollte.
Gruß Brainiac
-
Eine WM_TIME kann sich nicht in 1 ms wiederholen. Dies schafft Windows nicht da es kein Echtzeit-BS ist. Selbst wenn Windows selbst "nichts" zu tun hat oder man den schnellsten Rechner hat.
Ist schon lange her da hat jemand gepostet was die kürzeste Zeit ist wo Windows eine Nachricht auslösen kann. Kann mich erinnern das es bei ca. 20 ms oder bei ca. 50 ms liegt.
Dafür gibt es ja den Multimediatimer.
-
Brauchst du denn unbedingt eine Genauigkeit von 1ms???
Im Prinzip schon. Überleg mal: In "Super Mario Bros." braucht Mario, um den Bildschirm einmal von links nach rechts zu durchlaufen (wenn man sich jetzt mal das Scrolling wegdenkt und wirklich nur die Breite eines Bildschirms nimmt) drei Sekunden bei pixelgenauer Bewegung (also ohne daß ihn ein Druck aufs Steuerkreuz gleich 10 Pixel weiterbewegen würde). Wenn ich ein Programm schreibe, wo ich als Bild einen Screenshot aus "Super Mario Bros." und als Sprite Mario selbst nehme und ihn ebenfalls von links nach rechts laufen lasse (bei einer Schrittweite von einem Pixel, logischerweise) benötigt er mindestens 12 Sekunden. Das ist viermal mehr als im richtigen Spiel.
(Ich habe übrigens nicht vor, ein Remake von "Super Mario Bros." zu programmieren. Die Bilder daraus hab ich nur für das Testprogramm genommen.)Mach das, was zwischen zwei Frames zu tun ist, miss nach, wie lange das gedauert hat, und bewege dann das Männchen um eine Strecke, die dieser Zeit entspricht.
O.k., werd ich wohl mal ausprobieren.
-
Aber selbst wenn du es schaffen solltest, die Position der Spielfigur jede Millisekunde neu zu berechnen sieht der Spieler von dieser Genauigkeit doch wahrscheinlich nichts, da du ja auch keine 1000 WM_PAINT Nachrichten pro Sekunde verarbeiten kannst. Und eine pixelgenaue Berechnung ist bei Desktop-Auflösungen >1000 Pixel doch auch etwas anderes, als bei einem GameBoy, der wahrscheinlich nicht mal 100 Pixel breit ist.
Was spricht denn gegen ein längeres Intervall mit einer Bewegung um gleich mehrere Pixel?
50ms wären immerhin 20Frames/s , ich denke mal arg viel mehr ist sowieso nicht drin, oder?
-
25 Bilder pro Sekunde sind imho für das menschliche Auge eine flüssige Bewegung.
Mehr macht das Fernsehen doch auch nicht.
-
Aber selbst wenn du es schaffen solltest, die Position der Spielfigur jede Millisekunde neu zu berechnen sieht der Spieler von dieser Genauigkeit doch wahrscheinlich nichts, da du ja auch keine 1000 WM_PAINT Nachrichten pro Sekunde verarbeiten kannst.
Ich will ja auch nicht, daß er sich jede Millisekunde bewegt. Aber 256 Pixel in drei Sekunden ist ja nun wirklich nicht zu viel verlangt. Es ist ja nicht so, daß eine derartige Geschwindigkeit generell nicht möglich wäre. Wenn ich
for (int i=1; i<=256; i++) BewegungWasAuchImmer ();
schreibe, geht er ja auch sofort ab und schafft die Strecke in veniger als einer Sekunde. Und ich wette, wenn ich ihn in Abhängigkeit von clock () oder GetTickCount () bewege, wird das auch was. Mir fehlt eben nur eine Position, wo ich ständig überprüfen kann, ob clock ()-Startzeit>=Intervall und schon dürfte das Problem gelöst sein. Ich brauche eine Funktion, die parallel zum Programm entweder ständig neu aufgerufen wird oder durch eine Endlosschleife läuft (ohne daß das ganze Programm stehen bleibt), in die ich die Prüfung schreiben kann. Wenn alles nichts hilft, muß ich einen eigenen Thread starten, aber bevor ich das mache, wollte ich eben nach Alternativen gucken.
Gibt es keine Windows Message, die jedesmal aufgerufen wird, wenn sich die Rechnerzeit (in Millisekunden :-)) ändert? Dann schreibe ich das ganze doch so:DefWndProc (/*...*/) { if (msg==WM_PC_TIME_CHANGED_OR_SOMETHING_LIKE_THAT) if (clock ()-Start>=Intervall) { Bewegung (); Start+=Intervall; } //... }
25 Bilder pro Sekunde sind imho für das menschliche Auge eine flüssige Bewegung.
Es geht nicht um die Bilder pro Sekunde, sondern um die Zeit zwischen zwei Aufrufen der Bewegungsfunktion. Um die Ausgabe (mit OnPaint etc.) geht es mir gar nicht. Da besteht nämlich kein Problem.
-
Ich glaube du bist besser im "Spieleprogrammierung" Unterforum aufgehoben.
-
(ohne daß das ganze Programm stehen bleibt)
Was macht denn dein Programm noch ausser das Spiel?
-
Ich glaube du bist besser im "Spieleprogrammierung" Unterforum aufgehoben.
Nicht unbedingt. Es geht hier ja primär um den Timer. Daß ich ein Spiel programmieren will, ist zwar dann die praktische Anwendung, aber das Problem selbst hat erstmal nichts mit Spieleprogrammierung zu tun, sondern es geht einfach nur um Zeitintervalle.
-
(ohne daß das ganze Programm stehen bleibt)
Was macht denn dein Programm noch ausser das Spiel?
Es ging mir in dem Satz nur darum, daß eine Endlosschleife im Normalfall die ganze Anwendung anhält.
-
NES-SPieler schrieb:
Ich glaube du bist besser im "Spieleprogrammierung" Unterforum aufgehoben.
Nicht unbedingt. Es geht hier ja primär um den Timer. Daß ich ein Spiel programmieren will, ist zwar dann die praktische Anwendung, aber das Problem selbst hat erstmal nichts mit Spieleprogrammierung zu tun, sondern es geht einfach nur um Zeitintervalle.
Öhm ja aber das Problem hat uns ja MFK schön dargestellt, und ich denke drum, dass es nun um die bessere Strategie geht also wie-bewege-ich-die-Figur-Strategie (was MFK auch schon beantwortet hat. Und das ist schon besser im SpieleForum aufgehoben
-
Aber in normalen Spielen läuft das ganze Spiel halt in dieser Endlosschleife ab.
Und dann wird normalerweise per QueryPerformanceCounter die Zeit gemessen die vergangen ist.
-
Öhm ja aber das Problem hat uns ja MFK schön dargestellt
Klar, aber weil noch einige über den Timer geschrieben haben, bin ich weiter darauf eingegangen.
-
Kurz zur Info:
Die Hardware-Clock auf der die Window-Timer begründet sind haben eine Taktfrequenz von 54.9 ms . Sprich Du benötigst für 220 Ticks ca. 12,078 s kleinere Zeitintervalle werden auf die 54.9 ms aufgerundet. D.h. bei 1ms Schrittweite wird trotzdem in 54.9 Schritten eine Msg geworfen greetz...
-
@ Yogibear: Kannst du noch mal verraten, woher du das hast? Ich habe es auch schon mal gelesen, kann mich aber nicht dran erinnern, wo das war?!?