Wie relisiert man pixel- und frameunabhägige Berechnungen der Spielsituation?



  • Ich habe vor, den Spielstatus unabhängig von der Framerate und der Pixelgröße zu speichern. Doch ich hätte dazu einige Fragen.

    1. Stellen wir uns mal vor, das Spielfeld ist in 10 x 10 Einheiten unterteilt, wobei eine Einheit der Größe einer Spielfigur entspricht. (Das heißt, man könnte 10 Figuren nebeneinander packen.) Aber wie speichert man nun am besten die Position? Ich würde sagen, mit Kommazahlen. Ist das soweit richtig? Wenn ja: Kann es durch die Ungenauigkeit von float und double da nicht zu Problemen kommen? Wenn die Figur zweimal 0,5 Positionen läuft, bin ich wahrscheinlich genau an Position 1. Aber was ist, wenn ich sagen wir mal 1/7 einer Einheit laufe? Werden wir dann nach sieben Mal auf jeden Fall bei 1,0 ankommen, oder doch vielleicht bei 0,9999997?

    2. Bei frameunabhängigen Bewegungen misst man ja, wieviel Zeit seit dem letzten Abfragen verstrichen ist und bewegt die Figur dann entsprechend. Hier hab ich jedoch zwei Probleme:
    Erstens: Wenn der Computer laggt und nicht mehr hinterherkommt, würde ich erhoffen, dass er das Bild einfach einfriert bzw. in Zeitlupe weitermacht, bis er wieder die korrekte Geschwindikeit kann. Durch besagte Methode läuft das Spiel aber konstant weiter bzw. wird im Nachhinein rückwirkend berechnet. Das heißt, wenn der Computer mal für 20 Sekunden zu beschäftigt ist, um das Spiel weiter darzustellen, sehe ich, wenn er wieder OK ist, nur, wie mich der Gegener platt gemacht hat, weil er mal eben in einer Millisekunde berechnet hat, was in den letzten 20 Sekunden passiert wäre und mir dann das letzte Bild anzeigt.
    Zweitens: Wie soll ich die Aktionen von Figuren berechnen? Bei einer framebasierten Berechnung der Spielsituation ist ein Frame ja quasi die kleinste Zeiteinheit und ich kann pro Frame berechnen, was als nächstes passiert. Aber wie funktioniert das bei einer zeitgesteuerten Spiellogik ohne eigentliches Zeitminimum? Wenn sich eine Figur nur geradeaus bewegt, geht das ja noch. Aber sagen wir mal, die Grafik wird alle fünf Sekunden (Extremwertbetrachtung) ausgegeben: Wie berechne ich, dass eine Figur in der Zeit zwei Schritte nach links gelaufen ist, dann einen Schuss abgefeuert hat und dann weiter nach oben gelaufen ist? Wie soll ich auch nur annähernd komplexe Bewegungen berechnen, wenn ich keine kleinste Zeiteinheit, sondern nur die Differenz zwischen zwei Abfragen habe?



  • Gamerolaf schrieb:

    1. Stellen wir uns mal vor, das Spielfeld ist in 10 x 10 Einheiten unterteilt, wobei eine Einheit der Größe einer Spielfigur entspricht. (Das heißt, man könnte 10 Figuren nebeneinander packen.) Aber wie speichert man nun am besten die Position? Ich würde sagen, mit Kommazahlen. Ist das soweit richtig? Wenn ja: Kann es durch die Ungenauigkeit von float und double da nicht zu Problemen kommen? Wenn die Figur zweimal 0,5 Positionen läuft, bin ich wahrscheinlich genau an Position 1. Aber was ist, wenn ich sagen wir mal 1/7 einer Einheit laufe? Werden wir dann nach sieben Mal auf jeden Fall bei 1,0 ankommen, oder doch vielleicht bei 0,9999997?

    Entweder float/double oder Festkommazahlen. Bei float hast du evtl. Probleme wegen den Ungenauigkeiten. Bei Festkommazahlen zwar auch, aber hier reproduzierbar immer die gleiche Auswirkung, bei floats sind die Fehler relativ. Also 0 + 1/7 + 1/7 + 1/7 ... = 0.99 und 100 + 1/7 + 1/7 + 1/7 ... = 100.92 beispielsweise.

    Gamerolaf schrieb:

    Wie soll ich auch nur annähernd komplexe Bewegungen berechnen, wenn ich keine kleinste Zeiteinheit, sondern nur die Differenz zwischen zwei Abfragen habe?

    Am besten gar nicht. Die einzig sinnvoll anwendbaren Strategien sind fester Zeitschritt oder variabler Zeitschritt im Bereich von a-b (z.b 0.1s bis 0.005s).



  • Das ganze sollte auf jeden Fall in festen Schrittgrößen rechnen.
    Meistens ist es ja so, dass der Rendervorgang auf schwächeren Systemen am zeitaufwendigsten ist und man nach dem Bild dann mehrere Schritte berrechnen muss. Also Rendersystem und Simulationslogik(z.B. Physik) voneinander getrennt sind.
    Bei sehr schnellen Systemen hingegen kann nach einem bild noch jede menge Zeit über sein in der man noch keinen neuen Schritt berrechnen möchte.

    Diese Variante verwende ich oft für spiele und der gleichen.

    someVariableType lastStepTime = getTime();
    
    //game loop
    while(true)
    {
      handleInput();
      //für jede vergangenen 50ms wird ein Schritt berrechnet
      if (getTime() - lastStepTime > 50)
      {
        oneStepLogic();
        lastStepTime + 50;
      }
      RenderStuff();
    }
    

Anmelden zum Antworten