Feste Spielgeschwindigkeit



  • Wobei wir damit schon beim Netcode sind wo wir eigentlich nicht hin wollten 😉



  • trooper schrieb:

    @hustbär
    Und RedPuma hat eine Interpolation beschrieben zwischen zwei Positionen. Hier von einem Integral zu sprechen ist schon starker Tobak.

    Ich schreibe in dem Zusammenhang auch nicht von einem Integral.

    Vielleicht liest du mein Posting einfach nochmal. Die Berechnung der "Flugbahn" beim Springen ist von der Sache her die numerische Lösung eines Integrals. Also wenn man es so macht wie in meinem Beispiel.

    Ich schreibe im Übrigen sowieso nirgends von Interpolieren, das kommt immer von anderen.
    Interpolieren ist gaga, das macht man erst wenn man muss. Oft genug muss man nicht, dann macht mans nicht.



  • trooper schrieb:

    Ich denke dass wir aneinander vorbeireden, denn bei mir wird der Sprung in einzelne Schritte unterteilt und nicht als Ganzes berechnet. Zwischen diesen Einzelschritten wird pro Frame interpoliert.

    Haben die Einzelschritte bei dir eine fixe Zeit, oder variable Zeit?



  • So ich habe das jetzt mal mit dem Interpolieren ausprobiert.
    Und meine Positionsberechnung sieht jetzt so aus:

    int dest = 700;
    x = dest + time * (x - dest);
    

    Immer wenn ich jetzt die rechte Pfeiltaste drücke bewegt sich mein Objekt richtung Zielpunkt.
    Allerdings viel zu schnell.
    Und jetzt meine wieder eine Frage. Wie schaffe ich es, dass sich das Objekt immer gleich schnell bewegt, egal ob der Zielpunkt 700,800 oder 10000 ist?



  • Indem du den Richtungsvektor ausrechnest, normalisierst, mit der gewünschten Geschwindigkeit multiplizierst, und dann als Geschwindigkeits-Vektor verwendest?



  • Ich habe das folgende codesample mal auf floats geändert da du sonst Probleme bei sehr kleinen Zeitwerten hast.

    float dest = 700.0f; //Absolute destination
    float speed = 50.0f; //Moving 50 pixels per second
    float nextposition = x + speed*time;
    if( nextposition > dest )
        x = dest;
    else
        x = nextposition;
    

    "x" muss hierbei natürlich auch ein float sein.

    /Edit: Wenn du "dest" hierbei während der Programmlaufzeit ändern willst und destnew < destold dann solltest du in der if-Abfrage noch hinzufügen ob sich das Ziel links oder rechts von der aktuellen Position befindet.
    /Edit2: Ich gehe davon aus dass "time" die Zeit ist, die während eines Frames vergeht (Δt) und nicht die absolute Systemzeit.



  • @RedPuma
    Der Code ähnelt ziemlich meinem alten. Ich habe zwar noch nichts ausprobiert, ob der zittert aber antstatt sich 50 Pixel pro Sekunde zu bewegen, bewegt sich das Objekt nur 25 Pixel pro Sekunde.



  • Dann stimmt was mit deiner Zeitvariablen nicht.



  • Ich habe jetzt einmal für Release kompiliert, und schon klappt alles, auch beim Debuggen.
    Einziges Problem jetzt ist eben dieses Zittern, wenn ich die Bewegung von den Tastatureingaben abhängig mache.
    Nebenbei: Die Positionberechnung mit Interpolation, wie ich sie einmal in meinem Code verwendet habe ist ziemlicher schwachsinn. Angenommen der aktuelle Punkt ist 0, und der Zielpunkt ist 700. Dann würde nach der Rechnung mit der Framezeit von 0,03 Sekunden folgendes rauskommen:
    700 + 0,03 * (0 - 700) = 679
    Das Ergebnis danach wäre dann 699,37. Also so kann man eine Position nicht ausrechnen. Deswegen stelle ich mir schon die ganze Zeit die Frage, wie das korrekt mit Interpolation geht.



  • Eventuell zitterts weil du in deiner Timer Klasse mit 1/frequency multplizierst. Das könnte vielleicht Rundungsfehler geben da 1/frequency schon eine sehr kleine zahl ist.
    /Edit:
    Da das Ganze irgendwie ein wenig komplizierter wird kannst du, wenn du willst, mir auch gerne deinen Code per Mail schicken, dann kann ich mal reinschauen. (graefemarius at web . de)
    Außerdem würd mich selber interressieren warum des immer noch nicht funktioniert.



  • Pikkolini schrieb:

    Dann würde nach der Rechnung mit der Framezeit von 0,03 Sekunden folgendes rauskommen:
    700 + 0,03 * (0 - 700) = 679

    Das ist richtig, denn du hast dich 700 * 0,03 = 21 Einheiten in dieser Zeit bewegt.



  • @Interpolation und allgemeine Diskussion von wegen HL Engine

    Habe ich gerade eben gestern gelesen und fands noch ganz interessant:
    http://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
    http://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization



  • @nurf
    Dank dir habe ich jetzt endlich mein Denkfehler entdeckt.
    Wenn ich z.B. aus Position 20 stehe muss das x = 20 + 0,03 * (700 - 0) heißen.
    Bisher habe ich es immer so gemacht: x = 20 + 0,03 * (700 - 20).
    Mein Code sieht jetzt so aus:

    void object::move(short direct, short pps, double time) {	
    	short windowwidth = 800;
    	short windowheight = 600;
    
    	switch(direct) {
    		case 0x25:
    		{
    			x = x - ((time * windowwidth) * (1.0 / windowwidth)) * pps;
    			if (x < 0)
    				x = 0;
    			break;
    		}
    		case 0x26:
    		{
    			y = y + ((time * windowheight) * (1.0 / windowheight)) * pps;
    			if (y > windowheight)
    				y = windowheight;
    			break;
    		}
    		case 0x27:
    		{
    			x = x + ((time * windowwidth) * (1.0 / windowwidth)) * pps;
    			if (x > windowwidth)
    				x = windowwidth;
    			break;
    		}
    		case 0x28:
    		{
    			y = y - ((time * windowheight) * (1.0 / windowheight)) * pps;
    			if (y < 0)
    				y = 0;
    			break;
    		}
    	}
    };
    

    Wobei windowheight und windowwidth die Fensterhöhe und breite sind, direct die Richtung (VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN), pps die Pixel pro Sekunde und time die Zeit vom letzten Frame sind/ist.
    Die Funktion move rufe ich so auf:

    if (isKeyDown(VK_LEFT)) {
    	objects.move(VK_LEFT, 10, time);
    }
    if (isKeyDown(VK_UP)) {
    	objects.move(VK_UP, 10, time);
    }
    if (isKeyDown(VK_RIGHT)) {
    	objects.move(VK_RIGHT, 10, time);
    }
    if (isKeyDown(VK_DOWN)) {
    	objects.move(VK_DOWN, 100, time);
    }
    

    Allerdings bewegt sich das Objekt nur richtig, wenn ich die Pfeiltaste nach unten drücke. Drücke ich nach links, oben oder rechts bewegt sich das Objekt nur sehr langsam.
    Bis auf die Geschwindigkeit in manche Richtungen funktioniert bisher alles ohne Zittern so wie es soll.

    @RedPuma:
    Bis auf das Zittern hat ja eigentlich alles funktioniert.
    Und danke für das Angebot, doch ich denke das hat sich hiermit erledigt.
    Ansonsten hätte ich es gerne angenommen 🙂



  • trooper schrieb:

    "...das ist wirklich was anderes..."
    Mathematisch gesehen ist es das gleiche (siehe Beschreibung von mir). 😉
    Und mit Nichten ein Integral. 👎

    Aber Hallo ist das ein Integral. Das ist eine eingliedrige Taylorreihe die du da berechnest. Nimmst du einen Wegpunkt mehr, hast du sogar 2 Integrale in der Taylorreihe 😉 Es gibt nicht viele Wege, sowas mathematisch korrekt zu machen, und eigentlich führt kein Weg an einer Integration über die Zeit vorbei. Ist nur die Frage, wie exakt man das INtegral berechnet.

    //edit was spricht eigentlich gegen 2 Threads, in der der eine konsequent rendert und der andere einfach in festen Abständen seine Logikframes macht? Unter der Annahme, dass Berechnungszeit(logik)<<Berechnungszeit(Grafik) sollte damit doch alles ziemlich gut laufen, oder? Ich meine zumindest, solange man keine uralten PCs noch berücksichtigt. Für die Zukunft ist man damit aber abgesichert.



  • Also zuerst ein Tipp zu Leserlichkeit, ich würde anstatt der Hexzahlen in dem Case-Statement auch die VK_* Definitionen einsetzen.

    Zu deinem Problem: Das sich das Objekt sehr viel langsamer bewegt ist doch laut deinem Funktionsaufruf gewollt oder? Da rufst du nämlich die Funktion bei allen andern Keys außer VK_DOWN mit 10 anstatt 100 pps auf.



  • RedPuma schrieb:

    Also zuerst ein Tipp zu Leserlichkeit, ich würde anstatt der Hexzahlen in dem Case-Statement auch die VK_* Definitionen einsetzen.

    Danke für den Tip, das werde ich machen

    RedPuma schrieb:

    Zu deinem Problem: Das sich das Objekt sehr viel langsamer bewegt ist doch laut deinem Funktionsaufruf gewollt oder? Da rufst du nämlich die Funktion bei allen andern Keys außer VK_DOWN mit 10 anstatt 100 pps auf.

    Das habe ich total übersehen 🙄
    War halt schon was später und ich war müde, und hab mich dabei nurnoch auf den Code von der move-Funktion konzentriert.
    Das Zittern sehe ich in der Form eines "Schweifes" immernoch. Also Die Kanten werden 2 mal gezeichnet. Eine die man immer sieht, die zweite um einen Pixel verschoben, welche flackert.
    Ein Rundungsfehler kann natürlich die Ursache sein, aber ich weiß nicht genau wie C++ da rechnet.
    Wenn ich als Auflösung den Wert 2.7936511484001459e-007 habe, rechnet das System dann so:
    1 * 0,00000027936511484
    oder so:
    1 * 0,00000027936511484001459
    Und da bei Microsoft ein long double das gleiche wie ein double ist, weiß ich auch nicht wie ich das genauer hinbekommen soll.



  • Öhm das mit der Genauigkeit bei Fließkommazahlen ist eine ganz eigene Geschichte, die sind nämlich in der "Mitte", also um 0 herum am genausten. Nach "Außen" werden die etwas ungenauer, ist aber egal weil du dich hier ja um die 0 rum befindest.

    Ich hatte schonmal geschrieben dass durch die 1/frequency Rechnerrei und anschließende Multiplikation eventuell Rundungsfehler entstehen könnten. Du könntest mal ausprobieren den Frequency Wert direkt zu speichern und dann durch diesen zu teilen.



  • Hier eine Verdeutlichung des Problems einen Sprung ohne feste Anzahl an Rechenschritten zu berechnen.

    Ein schneller Rechner schafft mehr Approximationsschritte (die kürzer sind) als ein langsammer Rechner.

    Das Problem ist aber, dass bei einer guten Approximation einer Kurver durch Strecken, die Summe dieser Strecken größer ist als bei einer schlechteren Approximation.
    Das hat zur Folge das die Sprunghöhe auf einem schnellen und langsammen Rechner nicht gleich ist, wenn der Scheitelpunkt der Kurver z.B durch Aufaddieren der Streckenabschnitte berechnet wird.

    Bild:
    http://img716.imageshack.us/img716/1867/approximation.jpg
    (Das Bild ist nur eine Skizze und entspricht nicht den mathematisch exakten Höhenverhältnissen)


  • Mod

    ja, wenn man sich ein wenig damit beschaeftigt, wird einem klar weshalb variable zeitschritte sehr instabil sein koennen (lernt man eigentlich auch im physik unterricht wenn man beschleunigung usw durcharbeitet).

    und dass selbst feste zeitschritte oft nicht genug sind wird hier erklaert:
    http://wiki.vdrift.net/Numerical_Integration

    deswegen laeuft wohl jede physic engine mit festen zeitschritten (bzw mit maximalen schritweiten und einem guten solver).



  • Pikkolini schrieb:

    Das Zittern sehe ich in der Form eines "Schweifes" immernoch. Also Die Kanten werden 2 mal gezeichnet. Eine die man immer sieht, die zweite um einen Pixel verschoben, welche flackert.

    Kannst du deinen Code mal irgendwo hochladen?
    Vielleicht liegt es auch einfach nur an der Art wie du zeichnest.


Anmelden zum Antworten