Steuerung des Bewegungsflusses bei einem Netzwerkspiel

anfänger15

Bekanntes Mitglied
Hallo zusammen

ich bin gerade dabei als Schuleprojekt ein PingPong Spiel übers Netzwerk zu programmieren.
Dabei gibt es einen Server und 2 Clients pro Spiel.

Die Clients senden bei einem Tastendruck diese Information an den Server.
Der Server fürt die Berechnungen aus und sendet dann die Geschwindigkeit mit der sich das Objekt bewegt zu den Clients.

In bestimmten Zeitabständen wird zusätzlich die aktuelle exakte Position des Objekts vom Server an die Clients gesendet.
Die Bewegung von Objekten wird also gleichzeitig von Server und Clients ausgeführt und immer wieder synchronisiert.

Das Problem ist nun, dass der Server den Loop schneller abarbeitet als der Client (Der Client muss die Objekte auch neu zeichnen).
Außerdem kommt es auch vor, dass der Loop einmal schneller und einmal langsamer abgearbeitet wird. Hierfür merke ich mir die Zeit, die das durchlaufen des Loops benötigt hat und errechne mithilfe der Zeitdifferenz zwischen 2 durchläufen und der Bewegungsgeschwindigkeit des Objekts die aktuelle Position.

Es ist nun kein Problem, wenn der Loop einmal schneller bzw. langsamer durchlaufen wird, jedoch schaffe ich es nicht den "schnelleren" Server mit dem "langsameren" Client zu synchronisieren ohne das bei der Übertragung der aktuellen Position große Sprünge entstehen.

Zum Synchronisieren benötige ich zusätzlich das Delta des Servers, jedoch ist dafür das Netzwerk zu langsam.

Wie wird das in anderen Netzwerkspielen gelöst bzw. hat jemand eine Idee wie ich das lösen könnte?

Vielen Dank
 
Zuletzt bearbeitet:

anfänger15

Bekanntes Mitglied
Ich habe deinen Vorschlag mit dem request nun getestet, jedoch ist die Netzwerklast zu groß, wenn ich in jedem Loop einen request schicke. Außerdem habe ich auch noch eine zweite Idee von mir versucht, dabei schicke ich das Delta vom Server an die Clients und errechne mir mit dem Delta vom Server bei den Clients ein neues Delta. Das Problem hierbei ist nun auch wieder, das das Netzwerk zu langsam ist. Um dies zu vermeiden errechne ich den Durchschnitt der Deltas vom Server und übertrage nur diesen Durchschnittswert an die Clients. Dies ist aber zu ungenau.

Wenn also noch jemand eine Idee hat bin ich für jede Hilfe dankbar.
 

anfänger15

Bekanntes Mitglied
Ich will nicht unhöflich sein, jedoch würde ich das Projekt gerne abschließen und benötige daher bei o.g. Problem eure Hilfe.

Aufgrund der geringen Anworten (1 Antwort) schließe ich daraus, dass so ein Problem bisher noch nie jemand hatte, was ich mir nicht vorstellen kann.

Im schlimmsten Fall müsste ich das Spiel so umbauen, dass einer Server und einer Client vorhanden ist und der Server ebenfalls auf ein Panel zeichnet. Somit wären beide Loops annähernd gleich schnell. Dies will ich aber nur sehr ungern tun, da dadurch die klare Trennung zwischen Server und Client verloren geht.

Danke für jede Hilfe.
 

muckelzwerg

Bekanntes Mitglied
Sorry, ich verstehe das genaue Problem noch nicht.
"Der Client sendet bei Tastendruck <diese> Information an den Server."
Welche Information meinst Du?
Was genau versenden Client und Server für Informationen, während des Spiels? Und was berechnen sie auf ihrer Seite?

Deine "Lösung" mit einem zweiten Panel ist, entschuldige "ein dreckiger Hack" ;), der ganz schnell wieder auf die Nase fliegen wird, wenn sich die Leistung der Rechner oder des Netzwerks ändert.

Kannst Du nochmal genauer beschreiben, welche Berechnungen Client und Server ausführen und welche Informationen übertragen werden?
Grundsätzlich ist das kein so leichtes Thema, allerdings kommt man bei derart kleinen Beispielen oft mit simplen Lösungen aus.
Vielleicht haast Du schon gewonnen, wenn Du die Uhren der Rechner synchronisierst (NTP ...) und alle Nachrichten mit timestamps austauscht.
Du kannst hoffen, dass das Netzwerk keine wirkliche Rolle spielt und es nur ein nichtvorhandenes Synchronisationsprotokoll ist, das Deine Anwendung zerbröselt.

Ansonsten wirst Du Dich da nämlich erst reinwühlen müssen.
Gamasutra - Features - Dead Reckoning: Latency Hiding for Networked Games
http://www8.cs.umu.se/education/examina/Rapporter/HaishuZhang.pdf
architecture - Networking Pong Clone - Game Development - Stack Exchange
Simple online pong game network synchronization - Stack Overflow
...
 

anfänger15

Bekanntes Mitglied
Ok ich versuchs nochmal zu erklären.

Ich habe einen Server und 2 Clients.
Wird nun vom Spieler1 eine Taste gedrückt sendet der Client dem Server welche Taste gedrückt wurde.
Nun schaut der Server was beim Drücken der Taste passieren soll z.B. Spieler1 nach unten bewegen. Der Server verändert also die Geschwindigkeit des Spieler1 auf der Y-Achse und sendet die Geschwindigkeit, mit der sich der Spieler1 bewegt an beide Clients.
Die Änderung der Geschwindigkeit wird von beiden Clients empfangen und entsprechend gesetzt.

Es werden nun bis zur nächsten Bewegungsänderung von Spieler1 keine Daten mehr zwischen den Clients und dem Server ausgetauscht. Es wird lediglich zum synchronisieren der Clients mit dem Server in regelmäßigen Abständen die aktuelle Position (X,Y Koordinaten) vom Server an beide Clients gesendet.

Die Berechnung der aktuellen Position von Spieler1 wird nun unabhängig voneinander und anhand der Geschwindigkeit mit der sich Spieler1 auf der Y-Achse bewegt von beiden Clients und dem Server errechnet.

Zum berechnen der aktuellen Position von Spieler1 wird beim Client und Server die aktuelle Position mit der Geschwindigkeit verrechnet (z.B. Spieler1.Y = Spieler1.Y + Spieler1.SpeedY). Zusätzlich wird noch die Dauer des Durchlaufes eines Loops berücksichtigt.

Das Problem ist nun, dass der Server weniger Aufgaben (muss nicht auf ein Panel zeichnen) in seinem Loop hat als die Clients und daher den Loop öfters durchlauft. Folglich findet also die Berechnung der aktuellen Position auf dem Server öfters statt als auf den Clients. Aufgrund dessen hat sich der Spieler1 auf dem Server bereits viel weiter bewegt als bei den Clients. Es wird zwar wieder in regelmäßigen Abständen die aktuelle Position von Spieler1 des Servers an die Clients gesendet, jedoch ist die Differenz von Spieler1 auf dem Server und der Position von Spieler1 auf den Clients so groß, dass das Spiel nicht spielbar ist.

Ich habe das Spiel in einem kleinen Heimnetzwerk getestet und kann daher ausschließen, das das Netzwerk zu langsam ist. Mir ist bewusst, dass ich beim senden der akteullen Position vom Server an die Clients eine Verzögerung durch das Netzwerk habe und infolge dessen beim Empfangen so einer "Positionsnachricht" es bei den Clients "ruckelt", jedoch kann ich ausschließen das dies der Grund für die großen Sprünge ist.

Hoffe ich konnte es nun verständlicher erklären. Sollte noch etwas unklar sein einfach schreiben.

Danke
 

muckelzwerg

Bekanntes Mitglied
Da verbergen sich vermutlich einige Fehler. Aber erstmal ist da eine GANZ wichtige Sache, die Du ändern musst.
Die Position darf nicht von der Anzahl oder der Geschwindigkeit des Schleifendurchlaufs abhängen.
Du kannst nicht einfach in jedem Durchlauf einen bestimmten Wert aufaddieren. Ich schätze mal, Deine Geschwindigkeit, ist gar keine, sondern nur eine Zahl ohne Einheit, richtig?
Das heißt Du hättest zwar ganz gern, dass diese Zahl die Geschwindigkeit ist, sie ist es aber nicht. Die Geschwindigkeit der Objekte ist in diesem Fall die Geschwindigkeit des Schleifendurchlaufs und die Zahl die Du da verwendest nur ein zusätzlicher Faktor.
Läuft die Schleife langsam oder schnell, ist auch Dein Objekt langsam oder schnell. Läuft die Schleife gar nicht, oder pausiert für ein paar Takte, dann bewegt sich Dein Objekt nicht weiter und wird danach auch nicht springen.
Wenn die Schleife mal mehr zu tun hat (Panel zeichnen) wird natürlich Dein Objekt langsamer.

Geschwindigkeit bedeutet "Weg / Zeit". Ein Objekt hat eine Position, eine Bewegungsrichtung und eine Bewegeungsgeschwindigkeit.
Praktischerweise kann man Richtung und Geschwindigkeit in einem Vektor zusammenfassen. Die Richtung des Vektors entspricht der Bewegungsrichtung, die Länge des Vektors entspricht der Geschwindigkeit (z.B.)
Man kann es natürlich auch "getrennt" speichern. In Deinem Fall wird es wohl sowieso nur zwei Richtungen geben, wir reden doch von Pong oder?

Die Geschwindigkeit der Spieler/Schläger/Paddel ... musst Du in Weg/Zeit angeben. Die zurückgelegte Strecke errechnet sich dann aus der vergangenen Zeit seit der letzten Berechnung und dem Wert der Geschwindigkeit.
Führst Du die Berechnung hundert mal in der Sekunde aus, dann bekommst Du hundert Bewegungsschritte die alle ein Hundertstel des Weges pro Sekunde ausmachen.
An der Stelle musst Du schauen, ob Du Probleme mit Rundungsfehlern und zu kleinen Zahlen bekommst. Wenn Du Pech hast, werden die Einzelschritte so klein, dass beim Verändern der Position nichts mehr passiert, bzw. Ungenauigkeiten auftreten.
So ein "Kettenmaß" ist eigentlich nicht so besonders toll. Stattdessen ist es angenehmer immer auf einen gesicherten Startzeitpunkt mit einer gesichrten Startzeit zurückzurechnen.
Von diesem ausgehend wird dann mit der seither verstrichenen Zeit die aktuelle Position berechnet.
Damit auch hier kein langes Kettenmaß und eine zu komplexe Berechnung entsteht, aktualisierst Du den letzten sicheren Stand hin und wieder.
Beispeilsweise bei der Geschwindigkeitsänderung und/oder Richtungsänderung.
Das ist dann der "Keyframe".
 
Zuletzt bearbeitet:

anfänger15

Bekanntes Mitglied
anfänger15 hat gesagt.:
Zum berechnen der aktuellen Position von Spieler1 wird beim Client und Server die aktuelle Position mit der Geschwindigkeit verrechnet (z.B. Spieler1.Y = Spieler1.Y + Spieler1.SpeedY). Zusätzlich wird noch die Dauer des Durchlaufes eines Loops berücksichtigt.

Eigentlich müsste dies schon eine Geschwindigkeit sein.
Die genaue Berechnung sieht so aus:

Spieler1.Y = Spieler1.Y + (Spieler1.SpeedY * (Delta / 1e7))

Delta wird pro Schleifendurchlauf berechnet und entspricht der Differnz der vergangenen Millisekunden zwischen dem letzten Aufruf und dem jetzigen Aufruf.
 

Illuvatar

Top Contributor
Das ist etwas anderes als was du vorher geschrieben hast - und wenn du es so machst, bewegen sich die Spieler beim Server und beim Client gleich schnell, unabhängig von der Anzahl Schleifendurchläufe...

Abgesehen von eventuellen Ungenauigkeiten. Wie berechest du
Code:
delta
, mit
Code:
System.currentTimeMillis()
? Das kann, je nach System, recht ungenau sein - zu empfehlen ist
Code:
System.nanoTime()
.
Außerdem kannst du deine Berechnungen noch hierdurch verbessern:
muckelzwerg hat gesagt.:
So ein "Kettenmaß" ist eigentlich nicht so besonders toll. Stattdessen ist es angenehmer immer auf einen gesicherten Startzeitpunkt mit einer gesichrten Startzeit zurückzurechnen.
Von diesem ausgehend wird dann mit der seither verstrichenen Zeit die aktuelle Position berechnet.
Damit auch hier kein langes Kettenmaß und eine zu komplexe Berechnung entsteht, aktualisierst Du den letzten sicheren Stand hin und wieder.
Beispeilsweise bei der Geschwindigkeitsänderung und/oder Richtungsänderung.
Das ist dann der "Keyframe".
 

muckelzwerg

Bekanntes Mitglied
Da hat Illuvatar völlig recht. Was für Wiederholraten hast Du? Ich würde currentTimeMillis() nichtmal bei 30ms wirklich vertrauen.

Du kannst es ja sehr leicht testen.
Gib Dir eine feste Geschwindigkeit vor und lass die Schleife mal langsamer und schneller laufen.
Zum Beispiel "10 Einheiten pro Sekunde" (ich kenn Dein Bezugsystem nicht)
Dann lass die Schleife mit unterschiedlichen Wartezeiten laufen und die "Bruchstücke" der Bewegung anzeigen.
Nach 10 Sekunden musst Du da 100 Einheiten haben. Egal ob die Schleife einmal, 10mal, 100mal oder 300mal durchgelaufen ist.
Dafür brauchst Du kein Netzwerk, das kannst Du alles lokal testen.
 

anfänger15

Bekanntes Mitglied
Ich bin aufgrund der unterschiedlichen Positionen zwischen dem Server und dem Client davon ausgegangen, dass diese durch die unterschiedlichen Laufzeiten der Threads zustande kommen. Nach einigen Tests habe ich nun herausgefunden, das es doch am Netzwerk liegt. Es dauert zu lange bis der Client dem Server sendet welche Taste er gedruckt hat und der Server darauf dem Client die aktuelle Geschindigkeit zusendet. Da der Server nun schon früher mit den Berechnungen der Geschindigkeit anfägt ist er dem Client ein paar Pixel vorraus.
Ich werde nun also doch die Zeit, die das senden von Informationen zwischen Server und Client übrs Netzwerk braucht, berücksichtigen müssen.
Habt ihr noch ideen, was ich zwischen dem Client/Server Datenaustausch ändern/verbessern könnte.
Meine Idee, weshalb der Client nur die gedrücken Tasten sendet, war um zu verhindern, dass das Spiel zu einfach manipuliert werden kann. Dies wäre beim senden der aktuellen Geschwindigkeit durch den client kein Problem, da so jeder eine sehr hohe Geschwindigkeit senden könnte.

Danke für eure Hilfe. Das Forum hier ist echt klasse.
 

muckelzwerg

Bekanntes Mitglied
Uhren synchronisieren, da gibt es bestimmt ein "inline-ntp" für Java, oder was Vergleichbares.
Und dann bekommen die Pakete einen timestamp vom Versenden. Der dient als Basis der Berechnung seit wann sich das Objekt anders bewegt.

Dann miss aber auch mal die Netzwerkdrift. Rätselraten bringt da nicht viel. Du musst das Leck halt richtig finden, bevor Du es reparieren kannst.
Evlt. verschickst Du ja auch "unpraktisch" und must da nochmal was an der Rate etc. ändern.
 

anfänger15

Bekanntes Mitglied
Es läuft nun soweit, dass es "spielbar" ist jedoch "wackelt" der Ball immer noch beim setzten der Position auf den Clients, da diese durch die Übertragung übers Netzwerk veraltet sind. Die Lösung unter Berücksichtigung der Übertragungsdauer des Netzwerkes kenne ich nun und kann mithilfe deiner geposteten Links das Problem lösen.
Leider habe ich die nächsten Tage wenig Zeit, sodass ich dies nicht sofort umsetzen kann, sollte ich jedoch Probleme bei der Umsetzung haben werde ich mich wieder melden.
 

muckelzwerg

Bekanntes Mitglied
Es wäre bestimmt hilfreich, wenn Du am Schluss mal ein bisschen zusammenfasst, welche Probleme aufgetreten sind und wie Du sie gelöst hast.
Da würden sicher einige Einsteiger froh sein, wenn sie sehen, wie weit man bereits bei einem so einfachen Spiel manchmal gehen muss.
"Man denkt da leicht "das ist so simpel, das geht schon irgendwie" und dann ist es aber doch nicht so.
 
F

Firephoenix

Gast
Hi,
eine andere alternative wie man das realisieren könnte:

der server hat booleans die die clients beliebig steuern können (z.b. boolean spieler1hoch).
die spieler senden an den server per hoch/runter nur anfragen diese variablen zu ändern.
der server arbeitet einmal pro tick das spiel ab und bewegt die spieler entsprechend der variablen.
dann schickt er allen spielern den neuen spielstand usw.

Ich hab das ganze nie implementiert, aber das wäre mein Ansatz dafür, vielleicht hilft es ja trotzdem.
Gruß
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M BlueJ Schach Steuerung programmieren Spiele- und Multimedia-Programmierung 28
A Spracherkennung/steuerung Spiele- und Multimedia-Programmierung 12
staxx6 (Slick) Steuerung - mehrere Belegungen Spiele- und Multimedia-Programmierung 12
C Bluetooth Helikopter steuerung Spiele- und Multimedia-Programmierung 6
T Problem mit JnR-Steuerung / KeyListener Spiele- und Multimedia-Programmierung 6
D java 3d Steuerung (mit KSKB) Spiele- und Multimedia-Programmierung 9
L iTunes-Steuerung / Ereignisse abfangen Spiele- und Multimedia-Programmierung 2
R Problem Steuerung Spiele- und Multimedia-Programmierung 3
L 2 Spieler Steuerung Spiele- und Multimedia-Programmierung 4
E Rendering order auf einem ismetrischen Grid Spiele- und Multimedia-Programmierung 8
P Wie kann ich einem Programm hinter eine GUI verstecken? Spiele- und Multimedia-Programmierung 12
J (Libgdx) animation nur einmal in einem Event aufrufen Spiele- und Multimedia-Programmierung 1
B Programmieren wie der Befehl /ban in Minecraft geblockt wird aber nicht /ban mit einem Argument Spiele- und Multimedia-Programmierung 1
P selectedItem aus einem Methodenerstellten JPanel auslesen. Spiele- und Multimedia-Programmierung 5
O Problem beim Aufrufen des Spiels von einem Menü Spiele- und Multimedia-Programmierung 7
G Entity Verwaltung in einem 2D Spiel Spiele- und Multimedia-Programmierung 1
G Collision Detection in einem 2D Sandbox Game. Spiele- und Multimedia-Programmierung 2
E Einem A*-Pfad folgen Spiele- und Multimedia-Programmierung 27
G Auf einem Stick bewegen Spiele- und Multimedia-Programmierung 5
windl MP3-Tags von einem Inputstream auslesen Spiele- und Multimedia-Programmierung 5
U DPI von einem Bild definieren Spiele- und Multimedia-Programmierung 5
X Erklärung zu einem Tic Tac Toe Spiel Spiele- und Multimedia-Programmierung 1
C Hilfe bei einem Mosaikspiel Spiele- und Multimedia-Programmierung 16
M [JOGL] Maus über einem gezeichnetem Objekt abfragen? Spiele- und Multimedia-Programmierung 5
P Winkel von einem Punkt zum anderen berechnen Spiele- und Multimedia-Programmierung 9
X Kleines Problem mit Java Reflections und einem eigenen Eventhandler Spiele- und Multimedia-Programmierung 1
S Java3D: Primitives zu einem Objekt kombinieren Spiele- und Multimedia-Programmierung 7
Fl4sh1 Datum und Uhrzeit von einem Ereignis ausgeben lassen Spiele- und Multimedia-Programmierung 3
P Frage zu einem Projekt "Einarmiger Bandit" 3 Walzen / 9 Zeichnungen BLUEJ Spiele- und Multimedia-Programmierung 10
K Grundsätzlicher Spieleaufbau an (m)einem Beispiel Spiele- und Multimedia-Programmierung 4
S Problem mit Sichtfeld/Licht in einem Raster Spiele- und Multimedia-Programmierung 5
M Farbwerte für Flächen aus einem Bild erkennen Spiele- und Multimedia-Programmierung 3
A Drehen von einem Image Spiele- und Multimedia-Programmierung 4
F Bot updaten von einem Browser game Spiele- und Multimedia-Programmierung 7
W Java3D: Kanten die hinter einem Objekt liegen werden gezeigt Spiele- und Multimedia-Programmierung 2
B Reset bei einem Spiel Spiele- und Multimedia-Programmierung 16
C auf einem PC kein mp3 unter Java Spiele- und Multimedia-Programmierung 6
R Mehrere Shader in einem Program Spiele- und Multimedia-Programmierung 8
B Generierung einer Wertetabelle aus einem Bild Spiele- und Multimedia-Programmierung 3
Z Kugeln aufgrund von Daten aus einem Array verschieben Spiele- und Multimedia-Programmierung 2
S Probleme mit JMenu in einem JFrame mit BufferStrategy Spiele- und Multimedia-Programmierung 2
K Kanten anzeigen lassen in einem Shape3D-Objekt Spiele- und Multimedia-Programmierung 4
A Interaktion von J3D in einem Applet Spiele- und Multimedia-Programmierung 4
N In einem Kasten springende Bälle programmieren...Hilfe Spiele- und Multimedia-Programmierung 7
H Speichern und Öffnen von einem Zeichenprogramm Spiele- und Multimedia-Programmierung 4
A Wie kann ich die Dateigröße aus einem tiff auslesen? Spiele- und Multimedia-Programmierung 2
hdi mehrere Threads/Tasks in einem synchronisieren -> TaskPoo Spiele- und Multimedia-Programmierung 36
N Farberkennung und -ersetzung in einem Bild Spiele- und Multimedia-Programmierung 2
F Umsetzung von einem Partikelsystem Spiele- und Multimedia-Programmierung 4
J Java3D Rotationsproblem bei einem 3D-Maennchen Spiele- und Multimedia-Programmierung 3
B Frage zur Spielsteuerung bei einem rundenbasiertes Spiel Spiele- und Multimedia-Programmierung 5
K Seitenlänge aus einem Würfel lesen Spiele- und Multimedia-Programmierung 3
K Einzelne Pixel in einem Bild lesen Spiele- und Multimedia-Programmierung 5
T Kollisionsabfrage von einem Stein mit einem Ball Spiele- und Multimedia-Programmierung 5
G Einen gif oder jpg Datei aus einem Graphics Objekt o. JFrame Spiele- und Multimedia-Programmierung 2
A 3D Gegenstand in einem 2D Koordinatensystem darstellen. Spiele- und Multimedia-Programmierung 3
K Hilfe bei Grafikeinbindung in einem Spiel Spiele- und Multimedia-Programmierung 6
D Image.getGraphics() in einem Frame Spiele- und Multimedia-Programmierung 4
G Bufferimage bei einem Frame Spiele- und Multimedia-Programmierung 4
I Zweite Kamera in einem SimpleUniverse Spiele- und Multimedia-Programmierung 6

Ähnliche Java Themen

Neue Themen


Oben