Interpolieren von Positionen in einem Multiplayer-Spiel

14

Um in meinem Multiplayer-Spiel Bandbreite zu sparen , aktualisiere ich nicht jedes Objekt bei jedem Server-Tick, sondern jedes Objekt hat eine updateRate, die dem Spiel mitteilt, dass dieses Objekt voraussichtlich bei jedem X-Server-Tick aktualisiert wird.

Wenn ich eine Aktualisierungsnachricht für ein Objekt erhalte, berechne ich den Zeitpunkt, zu dem die nächste Aktualisierung eintrifft:

origin = serverCurrentPosition
diff = serverNextPosition - origin
arriveTime = now + timeBetweenTicks * updateRate

Wenn ich das Objekt zeichne, berechne ich die verbleibende Zeit bis zur nächsten Aktualisierung und interpoliere die Position entsprechend:

step = 100 / timeBetweenTicks * updateRate
delta = 1 - step * ((arriveTime - now) / 100)
position = origin + diff * delta

Es funktioniert ... aber es gibt immer noch ein bisschen Jitter in der Zeichnung, obwohl in meiner Theorie alles gut funktionieren sollte, da die Skalierung eine gewisse Verzögerung ausgleichen sollte, oder?

Die Frage hier ist also, ist dies der beste Ansatz? Soll ich die tatsächliche Verzögerung in die Berechnung einbeziehen? Wenn ja, wie würde ich das machen? Ich habe einige Experimente durchgeführt, aber der Jitter wurde nur schlimmer.

Ivo Wetzel
quelle
Hallo Ivo. Ich denke, das ist ein gutes Thema, aber es ist nicht klar, was Ihr Code tut - zum Beispiel woher kommen serverCurrentPosition, serverNextPosition, timeBetweenTicks?
CiscoIPPhone
Das sind die Update-Daten, die vom Server kommen.
Ivo Wetzel

Antworten:

11

Sie haben Jitter, weil Sie sich ständig ändern. Das heißt, während der Server genau alle timeBetweenTicksTicks aktualisiert , erhält der Client diese nach einer variablen Zeit. Diese Zeit ist wahrscheinlich in der Nähe timeBetweenTickseiner guten Verbindung, aber nicht genau gleich (und außerdem kann es zu Server-Verzögerungen und unterschiedlichen Taktraten auf Server und Client kommen).

Wenn Sie also darauf vertrauen, dass Sie das Update genau zur angegebenen Zeit erhalten, kommen Sie immer etwas vor / nach dem eigentlichen Update am Ziel an. Daher Jitter.

Ein einfacher Ansatz zur Reduzierung von Jitter ist die Verwendung von "Gummibändern", was Martin in einer anderen Antwort vorschlägt. Grundsätzlich ändert sich die Position des Objekts nicht sofort, wenn Sie eine Aktualisierung erhalten. Wenn sich die Clientposition und die Serverposition nur geringfügig unterscheiden, interpolieren Sie die Clientposition, sodass Client- und Serverposition nach einer bestimmten Zeit (etwa auf halbem Weg zur nächsten Aktualisierung) zusammenlaufen.

Eine weitere Idee zur Reduzierung von Jitter in Ihrem Setup: Da Sie sowohl "aktuelle" als auch "nächste" Koordinaten übertragen, können Sie die Geschwindigkeit des Objekts berechnen. Wenn die Aktualisierung verzögert ist, stoppen Sie das Objekt nicht an seinem Ziel (dh an der "nächsten" Position), sondern bewegen es mit derselben Geschwindigkeit weiter. Wenn Ihre Objekte ihre Geschwindigkeit nicht abrupt ändern, verbessert dies die Bewegungsruhe auf dem Client.

Keine Ursache
quelle
Es ist schon so, dass die Objekte nicht anhalten, sie bewegen sich weiter, bis sie das nächste Update erhalten. Außerdem scheint die Verwendung der Hardwarebeschleunigung im HTML-Canvas den Jitter-Effekt erheblich zu verringern. Vielleicht bin ich einfach verrückt geworden, nachdem ich so lange an dem Ding gearbeitet habe.
Ivo Wetzel
Das ist durchaus möglich. Wenn durch das Einschalten der Beschleunigung die Bildrate erhöht wird, steigt die Wahrscheinlichkeit, dass die Aktualisierungsinformationen genau zum richtigen Zeitpunkt verarbeitet werden.
Nevermind
9

Ich habe dieses Problem bereits mit einigem Erfolg mit einem Ansatz gelöst, den ich "Netzwerkschatten" nenne. Ich weiß nicht, ob das etwas ist, was andere Leute tun, aber es hat immer für mich funktioniert.

Jede Entität, die über das Netzwerk synchronisiert wird, verfügt über eine unsichtbare Netzwerkschattenentität. Wenn ein Update vom Netzwerk eingeht, teleportieren Sie den Schatten direkt an die Position, an der sich das Netzwerk befinden soll, und interpolieren dann langsam die lokal sichtbare Entität in Richtung des Schattens.

Ich habe in meiner vorherigen Antwort hier viele Details zu diesem Ansatz aufgenommen

Martin
quelle
Hm, ich habe so etwas in einer früheren Version gemacht, Gleitkomma-Ungenauigkeiten haben es manchmal sehr schlecht gemacht, ich habe ziemlich große Zeitspannen zwischen den Updates, bis zu 300ms für einige Objekte, aber vielleicht habe ich es einfach falsch gemacht, ich werde es geben ein Schuss, wenn ich etwas Freizeit finde :)
Ivo Wetzel
Fließkommapräzision sollte eigentlich gar nicht ins Spiel kommen! Haben Sie meine verknüpfte Antwort zum Stackoverflow gelesen? Es deckt alle Details der Implementierung solcher Dinge ab.
Martin