Wie das Programm ablaufen lassen?



  • Hallo,
    ich habe eine Frage zu der Programmlogik.
    Man soll ja bekanntlich in einem Spiel die Logik vom visuellen strikt unterscheiden.
    Da die beiden Schritte aber immer hintereinander ablaufen stellt sich mir eine Frage.
    Wenn ich z.B. alle 10ms die Logix neu berechnen will, aber VSync an ist, so behindert die Draw() Funktion ja Funktion zur Berechnung der Programmlogik.
    Wie löst man das Problem am besten? Wie machen das die Leute bei professionellen Spielen? Die vergangene Zeit pro Programmschritt zu messen und damit zu arbeiten kommt außer Frage, da dabei wegen der ungenauigkeit von Fließkommazahlen miestens unschöne Ergebnisse bei rauskommen.
    Und wie ist es mit Threads? Wie hoch ist da ca. der Aufwand, dass einem nicht alles um die Ohren fliegt und wie kann man eigentlich sichern, dass der Logik-Thread nicht wegen irgendwelchen Synchronisationen zu lange wartet?



  • Pikkolini schrieb:

    Die vergangene Zeit pro Programmschritt zu messen und damit zu arbeiten kommt außer Frage, da dabei wegen der ungenauigkeit von Fließkommazahlen miestens unschöne Ergebnisse bei rauskommen.

    Aha, das glaube ich weniger..
    Bin selbst lange kein Profi und lasse mich da auch gerne belehren, aber wie kommst du darauf dass Zeitmessungen zu ungenau wären?



  • Aus Erfahrnung.
    Beispielsweise lasse ich ein Viereck bewegen. Wenn ich zum berechnen der Position einen festen Tick benutze sieht es flüssig aus. Wenn ich den Timer benutze ruckelt es ein klein wenig.



  • Ich habe das so gelöst (verwende SFML):

    while (running && app.IsOpened())
    {
    	restTime += app.GetFrameTime(); //getframetime gibt zeit seit letzter zeichnung
    	while(restTime > updateRate)
    	{
                   //hier kommt die Logik rein
        }
        //zeichnen
    }
    

    Das sorgt dafür, dass du eine gewisse mindestanzahl an logikframes hast, es also auch bei rucklern keine größeren probleme gibt (ansonsten könnten "durcheinander bewegt werden" ohne zu kollidieren).
    Und das vorgehen sorgt dafür, dass auch mindestens 100 Logikframes pro sekunde gemacht werden, egal ob vsync an ist oder nicht.



  • ups hatte das mit der zeitmessung außer frage überlesen, sry.
    Aber ich kann aus erfahrung sagen, dass das keine probleme zu machen scheint.
    Leider kann ich nicht edit machen ohne registrierung, sollte mich vll langsam mal registrieren^^



  • Danke für deine Antwort.
    Die Idee mit der Schleife die mindestens 100 Logikframes garantiert scheint mir sinnvoll, aber ist es in deinem Beispiel keine Endlosschleife?
    Hab gerade irgendwie nen Brett vorm Kopf 🙄



  • Ne das ist keine Endlosschleife.
    Hätte vll eine Zeile mehr drinlassen sollen:

    restTime += app.GetFrameTime(); 
         while(restTime > updateRate) 
         { 
              restTime -= updateRate;  //<-- verhindert die endlosschleife
              //hier kommt die Logik rein 
         }
    

    Hoffe, es ist jetzt klar geworden.



  • Es ruckelt? Ich meine, die Logik wird dann ja genauso oft durchlaufen wie die Grafik, da dürfte es eigentlich nicht Ruckeln. Also so in der Art:

    if (GetMessage())
    {
    }
    else
    {
      object.pos += object.direction * object.speed * elapsedTime;
      Render();
    }
    


  • Es ruckelt wegen der ungenauigkeit von Fließkommazahlen.
    Das kann man sehr schön beobachten, wenn ich aus dem double ein float mache. Denn wenn ich zur Berechnung ein float nehme zittert das Objekt beim Bewegen ziemlich sichtbar, wenn ich double wenig nur ein ganz klein wenig.



  • Aha, aber Rotation etc. macht man doch auch mit floats? Ich kann mir irgendwie nicht vorstellen, dass man das sehen soll..
    Wichtig könnte sein, dass du nur die Objekte neu berechnest, also bewegst, die auch wirklich eine Bewegung haben. Du musst also garantieren dass der object.direction Vektor oder halt object.speed irgendwann einfach (0,0,0) bzw. 0 sind. Dann dürfte kein Wackeln zur sehen sein. Und neben einer "echten" Bewegung geht dass dann eh unter.

    Ansonsten würde mich mal ein simples Codebeispiel interessieren, ich kann das Problem irgendwie nicht ganz nachvollziehen..



  • In welcher Größenordnung befinden sich denn die Beträge der Koordinaten mit denen du deine Objekte jedes Frame bewegst? Die müssen sehr sehr klein oder sehr sehr groß sein, dass man da einen Unterschied aufgrund der Genauigkeit von float/double merkt (Minecraft benutzt z.B. diese v*t Methode und da kommt es wirklich zu Fehlern wenn man zu weit vom Mittelpunkt der Map wegläuft [da läuft man aber sehr lange]).

    Da scheint's mir wahrscheinlicher dass deine Zeitmessung vll. nicht genau genug ist. Wenn dein Frame nur ne halbe ms zum Durchlaufen braucht, deine Zeitmessung aber nur auf 1ms genau auflöst, merkt man das schon sehr stark.



  • Bei mir im Code siehts einfach so aus:

    x = speed * ticks;
    

    Ich benutz den PerfomanceCounter von der WinApi und komm auf ca. 16ms pro Frame.


Anmelden zum Antworten