Timer zu langsam



  • Polofreak schrieb:

    zeig doch mal die Funktion vielleicht hängts ja woanders 😕

    Ich kann mir das durchaus vorstellen. WM_TIMER ist für solche Anwendungsfälle nicht geeignet (und auch nicht gedacht).



  • OK tut mir leid, wenn MFK das sagt kannste davon ausgehen, dass da ziemlich nicht mehr viel zu machen ist (ich zieh meinen Hut vor MFK) Somit muss ich mich wohl an dieser Stelle zurück ziehen.



  • zeig doch mal die Funktion vielleicht hängts ja woanders

    Welche Funktion? Also ein konkretes Spiel hab ich momentan nicht vorliegen. Das ist mir nur mal beim Testen aufgefallen. Aber folgendes sollte auch reichen:

    //...
    
    void CMeinProgrammDlg::OnInitDialog ()
    {
        //...
    
        m_nZahl=0;
        m_nTimer=0;
    
        //...
    }
    
    void OnKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags )
    {
        if (m_nTimer==0) //Verhindert, daß der Timer mehrmals aufgerufen wird.
        {
            MessageBox ("Start");
            m_nTimer=SetTimer (1, 1, NULL);
        }
    
        //...
    }
    
    void OnTimer (UINT nIDEvent)
    {
        m_nZahl++;
    
        if (m_nZahl==220)
        {
            KillTimer (nIDEvent);
            m_nTimer=0;
            MessageBox ("Stop");
        }
    
        //...
    }
    
    //...
    

    Das sollte reichen, um es zu demonstrieren. Wenn Du nun die Zeit zwichen den beiden Message Boxen mißt, kommst Du auf circa 12 Sekunden. Und das ist zu lang. 220*1ms=220ms und nicht 12s.



  • Und den Streit solltest du lesen. C++ Freak versuchte uns zu erklären, wie man "richtige" Timer selber machen kann.

    Ja, aber seine Methode mit der Sleep-Funktion ist wirklich nicht die Lösung. Die hält nämlich das gesamte Programm an und ist kein Timer in dem Sinn.



  • Imho ist der Grund ganz einfach:

    So ein Timer ist ja eine Nachricht.
    Und wenn so ein Timer rausgeht, dann dauert das einen Moment, bis er ankommt. (Verzögerung 1)
    Dann hat dein Windows ja noch mehr zu tun als Timer verarbeiten, die müssen sich also hinten anstellen. (Verzögerung 2)
    Das was du in der Funktion machst, kostet auch nochmal Zeit.

    Ich meine irgendwo gelesen zu haben, dass man Werte unter 50 gar nicht erst nehmen braucht, weil Timer so ungenau sind.

    Du wirst dir wohl etwas anderes suchen müssen. 🙄



  • Nur mal so am Rande. Du kannst da zwar 1 ms angeben, aber irgendwo steht auch (oder ich habe es woanders gelesen), dass der kleinste zuverlässige Werte zwischen 10 und 100 ms liegt. Ich weiss, große Zeitspanne, bin mir aber bei dem genauen Wert nicht so sicher.Dann sind es im schlimmsten Fall 220*100 ms = 22000 ms = 22 Sek. Also ist es wahrscheinlicher das du so bei ca. 50ms liegst.



  • estartu_de schrieb:

    Und wenn so ein Timer rausgeht, dann dauert das einen Moment, bis er ankommt. (Verzögerung 1)
    Dann hat dein Windows ja noch mehr zu tun als Timer verarbeiten, die müssen sich also hinten anstellen. (Verzögerung 2)

    Timer-Nachrichten werden überhaupt erst dann abgearbeitet, wenn keine Nachrichten mit hoher Priorität in der Message Queue steht (Verzögerung 3)

    Es kann auch immer nur eine Timer-Nachricht in der Queue stehen -> Timer-Ereignisse gehen verloren.



  • NES-Spieler schrieb:

    Und den Streit solltest du lesen. C++ Freak versuchte uns zu erklären, wie man "richtige" Timer selber machen kann.

    Ja, aber seine Methode mit der Sleep-Funktion ist wirklich nicht die Lösung. Die hält nämlich das gesamte Programm an und ist kein Timer in dem Sinn.

    Tja, ab DER Stelle haben wir es ja auch nicht mehr verstanden. Er beharrte darauf, dass es trotzdem ginge und dann schief die Diskussion ein.



  • Zusatz zu Estartu:

    Und er bildete Nonsens-Phrasen um zu beeindrucken, so dass niemand mehr versteht was er da eigentlich behauptet 🙄 und niemand mehr was dazu sagt (zumindest das hat fast geklappt)



  • O.k., fragen wir doch mal so: Wie macht man das normalerweise, wenn man einen Timer braucht, der recht zügig sein soll? Wenn Ihr ein Männchen von links nach rechts bewegen wolltet, wie würdet Ihr das mit der Zeit zwischen zwei Schritten realisieren? Sleep, wie gesagt, funktioniert nicht und hält das ganze Programm an. Und die Version

    void OnKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags)
    {
        switch (nChar)
        {
        case VK_RIGHT:
            m_Spielfigur.GoRight (); //oder was auch immer
            break;
        case VK_LEFT:
            m_Spielfigur.GoLeft ();
            break;
        }
    
        CDialog:OnKeyDown (nChar, nRepCnt, nFlags);
    }
    

    ist ja auch nicht das Wahre, denn erstens sieht so eine Bewegung abgehackt aus und zweitens dürfte hier die Geschwindigkeit sowohl von der Geschwindigkeit des PCs generell als auch von der eingestellten Wiederholrate der Tastatur abhängen. (Nicht zu reden von computergesteuerten Gegnern, auf die diese Möglichkeit gar nicht anwendbar ist.)

    Also, was macht man in dem Fall? Irgendwie muß das doch gehen.

    P.S.: Bitte erklärt mir jetzt nicht, daß man mit der MFC keine Spiele programmiert! Das ganze Problem (der lahme Timer) könnte man nämlich auch auf reine WinAPI-Programme beziehen. Da ist es genauso.



  • 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. 😉


Anmelden zum Antworten