Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Netzwerk-Spiel-Kommunikation (https://www.delphipraxis.net/96737-netzwerk-spiel-kommunikation.html)

wicht 30. Jul 2007 10:08


Netzwerk-Spiel-Kommunikation
 
Hallo Delphi-Freunde!

So, ich hätte da mal eine kleine Frage und hoffe, ihr könnt mir dabei irgendwie weiterhelfen.. Ich habe ein Spiel gebaut, es besteht aus Server und Client, der Client schickt Bewegungsdaten des Spielers an den Server (z.B. Gehe-1-nach-oben), der Server kontrolliert diese Daten und wenn die Bewegung zeitlich erlaubt ist (damit sich nicht einer schneller bewegt als der andere) und die neuen Koordinaten okay wären, wird die neue Y-Position des Spielers an alle anderen Clients geschickt. Dann bewegt sich der Spieler überall, so wie es sein soll. Die Kommunikation erfolgt über die ICS-Sockets, übertragen tue ich nur Records die aus vielleicht 3 Bytes und einem Double/Integer bestehen, um die Datenmenge möglichst gering zu halten.
Das läuft auch ganz toll, ich war richtig begeistert, nur dann kam der Rückschlag: Lasse ich den Server auf einem anderen Computer laufen und verbinde mich dahin, ruckeln die Bewegungen irgendwie teilweise, z.B. bei der ersten Bewegung (Spieler drückt Taste-hoch und lässt sie gedrückt, dann stockt es am Anfang der Bewegung). Nach dem anfänglichen Stocken geht es dann aber ganz normal, nur das wiederholt sich natürlich immer und ist auf Dauer sehr nervig. Und das war nur im Netzwerk - übers Internet wird es dann wohl noch schlimmer sein...

Bevor ich jetzt an irgendelchen Sachen rumpfusche, wollte ich sicherheitshalber mal fragen, was ich da am besten machen könnte.. Irgendjemand hat soetwas vielleicht schon einmal gemacht?

Wäre sehr dankbar für Antworten :) ..

OregonGhost 30. Jul 2007 10:15

Re: Netzwerk-Spiel-Kommunikation
 
Überträgst du die Daten synchron, also wartest auf die Antwort, bevor dein Programm weiterläuft?

Bernhard Geyer 30. Jul 2007 10:19

Re: Netzwerk-Spiel-Kommunikation
 
Das Problem sind (soweit ich sehe) die Rount-Tripp-Delays. Jeder Netzwerkverkehr benötigt eine Zeit welche schon in den ms-Bereich gelangen kann. Teilst du deine Kommunikation in viele kleine "Häppchen" welche auch noch per TCP gesichert übertragen werden ist Ruckeln nicht mehr zu vermeiden.

- Für LAN-Lösung wäre ein Implementierung ohne Server vor Vorteil
- Kommunikation mit UDP statt TCP

Es gibt mit Sicherheite weiter Optimierungen, aber ich bin kein Spiele-Entwickler.

Nicolai1234 30. Jul 2007 10:31

Re: Netzwerk-Spiel-Kommunikation
 
Zitat:

Zitat von wicht
Ich habe ein Spiel gebaut, es besteht aus Server und Client, der Client schickt Bewegungsdaten des Spielers an den Server (z.B. Gehe-1-nach-oben), der Server kontrolliert diese Daten und wenn die Bewegung zeitlich erlaubt ist (damit sich nicht einer schneller bewegt als der andere) und die neuen Koordinaten okay wären, wird die neue Y-Position des Spielers an alle anderen Clients geschickt. Dann bewegt sich der Spieler überall, so wie es sein soll.

Könntest du die Bewegung nicht schon von dem Client machen lassen, an dem der Spieler sitzt? Der kann ja im Grund3e auch beurteilen, ob der Zug erlaubt ist. Die Daten gingen dann nur noch zur Kontrolle an en Server und um sie an die anderen Mitspieler weiterzuleiten. Ich denke, so könntest du ein ruckeln verhindern.

wicht 30. Jul 2007 10:38

Re: Netzwerk-Spiel-Kommunikation
 
Hallo!

Hätte so schnell nicht mit 2 Antworten gerechnet, super!

@OregonGhost: Synchron läuft nur Handshake und sowas ab. Das eigentliche Spiel nicht. Der Client ist angemeldet und schickt Tastatureingaben weiter, der Server verarbeitet diese. Sind die empfangenen Daten ungültig, wird der Client rausgeworfen und bekommt vorher eine Fehlermeldung zugeschickt.

@Bernhard Geyer: Also, ohne Server geht es nicht. Der muss auf jedenfall dabei sein. Daran hatte ich auch schon gedacht, aber ist leider nicht möglich. Tja, die Kommunikation läuft über TCP. Das heißt, ich sollte auf UDP umsteigen? Kleine Nebenfrage: Ist das per UDP bei den meisten Onlinespielen gemacht, die Übertragungen mit geringer Latenz brauchen? UDP verzichtet auf Korrektur von falschen Übertragungen - gibt es sonst noch Unterschiede, die sich eventuell auch nachteilig auswirken könnten?

@Nicolai1605: Klar könnte ich die auch vom Client aus machen. Aber nehmen wir an, ich habe 6 Spieler auf einer Karte und einer bewegt sich - Ob ich die Daten dann an die 5 anderen schicke, oder auch noch an den, der diese gesendet hat, macht den Kohl vermutlich nicht fett dachte ich mir. Ausserdem ist es weniger Arbeit :stupid: ...

Danke für die Antworten :thumb:

Nicolai1234 30. Jul 2007 10:47

Re: Netzwerk-Spiel-Kommunikation
 
Zitat:

Zitat von wicht
@Nicolai1605: Klar könnte ich die auch vom Client aus machen. Aber nehmen wir an, ich habe 6 Spieler auf einer Karte und einer bewegt sich - Ob ich die Daten dann an die 5 anderen schicke, oder auch noch an den, der diese gesendet hat, macht den Kohl vermutlich nicht fett dachte ich mir. Ausserdem ist es weniger Arbeit :stupid: ...

Das stimmt schon, aber de Figur bewegt sich bei dem Spieler sofort. Da entsteht kein ruckeln mehr. Und die anderen Spieler merken ja nicht, ob es eine Verzögerung zwischen Tastendruck es Mitspielers und der Reaktion sehen. Die wissen ja noch nicht einmal, dass derjenige gedrückt hat. Den Ruckler merkt doch nur derjenige, der auch die Taste drückt, oder?

OregonGhost 30. Jul 2007 10:55

Re: Netzwerk-Spiel-Kommunikation
 
Vielleicht ist für dich der Artikel über die Netzwerkimplementierung von Age of Empires bei Gamasutra interessant. Beschäftigt sich recht ausführlich mit den Problemen, auf die die Entwickler gestoßen sind (wenn auch weniger speziell mit Latenz).

Was Nicolai sagt, ist aber auch nicht unbedeutend, es geht dabei darum, auf dem Client schonmal "loszulaufen" in der Hoffnung, dass der Server sein OK nachträglich noch gibt. Dann hast du keine Verzögerungen auf Clientseite.

Und was ich oben mit synchron meinte, ist die Frage, ob du auf die Antwort des Servers wartest. Tust du es nicht, sollte auch kein Ruckeln entstehen.

wicht 30. Jul 2007 12:03

Re: Netzwerk-Spiel-Kommunikation
 
Achso, eine Kleinigkeit noch: Es ruckelt ja nicht direkt, aber wenn ich eine Bewegung anfange, z.B. von links nach ganz rechts über die Karte, dann hakt es nur ganz kurz beim Anfangen der Bewegung, der Rest läuft flüssig. Und jede Positions-Änderung kommt ja vom Server. Das finde ich irgendwie merkwürdig..

OregonGhost 30. Jul 2007 12:08

Re: Netzwerk-Spiel-Kommunikation
 
Du meinst jetzt aber nicht die Wiederholungsverzögerung der Tastatur, oder? :stupid:
Kannst du vielleicht den Ablauf vom Tastendruck über die Server-Verbindung bis hin zur Bewegung in Pseudocode zeigen?

wicht 30. Jul 2007 12:22

Re: Netzwerk-Spiel-Kommunikation
 
Nee, die meine ich nicht. Wenn ich Server und Client lokal laufen lasse, ist dieses "Ruckeln am Anfang" ja auch nicht mehr da.
Code kann ich zeigen, wenn ich wieder zuhause bin. Werde ich dann direkt machen ;-)

wicht 30. Jul 2007 16:01

Re: Netzwerk-Spiel-Kommunikation
 
So, der Code... also, Verbindung ist hergestellt, Client hat Erlaubnis bekommen und sowas, im Spiel wird eine Taste gedrückt:

Delphi-Quellcode:
if GetTickCount > LastKeyPress + INPUTDELAY then
  begin
    LastKeyPress := GetTickCount;
    if HiWord(GetKeyState(VK_LEFT)) <> 0 then
    begin
      SendActionData(atLeft);
    end;
  end;
Dann kommt SendActionData():

Delphi-Quellcode:
procedure TfrmMain.SendActionData(Action: TActionTypes);
var
  M: TActionMessage;
  V, DT: Byte;
begin
  V := PROT_ACTIONDATA;
  M.Action := Byte(Action);

  addSocket.Send(@V, SizeOf(Byte));
  addSocket.Send(@M, SizeOf(TActionMessage));
end;
So, jetzt werden die Dinger abgeschickt. Der Server sieht dann das PROT_ACTIONDATA, ließt den Record aus und macht quasi das selbe nur mit einem anderen Record. Das ließt der Client dann und passt die Position des Spielers an. Den Code könnte ich zwar auch noch zeigen, aber ich glaube nicht dass das weiterhilft. Falls das hier überhaupt weiterhilft...

Ich werde mal ein kleines Programm mit UDP-Kommunikation schreiben und testen, ob es da besser läuft. Achja: Ich habe gelesen, dass bei UDP die Daten auch in anderer Reihenfolge ankommen können - bedeutet das, dass mein Record eventuell in falscher Reihenfolge ankommt?! Also nicht erst das Byte an erster Stelle, sondern vielleicht zuerst der Double-Wert weiter hinten? Kann doch eigentlich nicht sein, oder? Oder muss ich es dann so machen, dass der Server immer ein UDP-Paket zurückschickt wo drin steht "Positionsdaten empfangen, lieber Client, nun darfst du die nächsten Koordinaten schicken"?
Naja, könnte sein, dass die Fragen dumm sind, aber ich werde mich erstmal weiter informieren...

shmia 30. Jul 2007 16:29

Re: Netzwerk-Spiel-Kommunikation
 
Zitat:

Zitat von wicht
Delphi-Quellcode:
procedure TfrmMain.SendActionData(Action: TActionTypes);
var
  M: TActionMessage;
  V, DT: Byte;
begin
  V := PROT_ACTIONDATA;
  M.Action := Byte(Action);

  addSocket.Send(@V, SizeOf(Byte));
  addSocket.Send(@M, SizeOf(TActionMessage));
end;

2 Mal .Send() könnte unter Umständen zu zwei Netzwerkpaketen führen, die einzeln auf die Reise gehen.
Bei UDP ist es sicher so.
Bei TCP sorgt das Betriebssystem jetzt nach Einstellung dafür, dass Daten
die kurz hintereinander der WinSock-API übergeben werden in ein Paket gepackt werden.
Deshalb alles in einem Record enthalten sein:
Delphi-Quellcode:
type
   TActionMessage = record
      MessageType : Word;
      Action : Byte;
      ...
   end;
   ...
   M.MessageType := PROT_ACTIONDATA;
   addSocket.Send(@M, SizeOf(TActionMessage)); // nur 1 "Send" nötig

jfheins 30. Jul 2007 16:38

Re: Netzwerk-Spiel-Kommunikation
 
Du solltest generell nicht alles zwangssynchronisieren,über den Server, wie du es jetzt machst Also nicht 5 Tastaturen, die einem Server Tastendrücke schicken, und der dann auf 5 Monitoren ausgibt.
Sondern du solltest den Tastendruck sofort ausführen, und den Server nur "benachichtigen".
Dann sollte der Server diese "Benachrichtigung" an alle anderen Clients weiterleiten (oder an ale, und der, ders gesendet hat, filtert es dann raus ...) und vll. einmal ale 3 Sekunden oder so eine komplette Übersicht über das Speilfeld um einer Desynchronisation vorzubeugen ...

Oder der Server antwortet auf jede Benachritigung mit der neuen Position, und die wird dann gesetzt. Wenn der Zug gültig war, bemerkt man keine Änderung, ansonsten wird der Fehler berichtigt. (Wobei natürlich schon der Client soviele ungültige Züge wie möglich verhindern sollte ...)

MfG,
Julius

wicht 30. Jul 2007 17:18

Re: Netzwerk-Spiel-Kommunikation
 
Jupp, da dachte ich auch dran. Aber habe ich erstmal nicht geändert. Der Typ des Records steht ja im ersten Send(), und weil beide Programme eine Unit für Datentypen benutzen wissen beide wie Groß die Daten sind. Ist auch egal wieviele Pakete das werden, alles kommt in einen Stream und anhand der Größe finde ich heraus, ob der Datensatz komplett ist. Das macht auch keine Probleme, ich will es ja nur funktionierend haben ersteinmal... Im Handshake werden auch die Versionen abgeglichen, da können sich die Records ruhig ändern, solange der THandshakeMessage-Record gleichbleibt denke ich.

Was mich wirklich interessiert ist jetzt eigentlich nur noch, wie stark die Daten bei UDP durcheinander gewürfelt ankommen können. Ich meine, wenn die verschiedenen Daten (=Records), die ich an Send() übergeben habe, in falscher Reihenfolge ankommen, ist das relativ egal. Brauche ich nur für den Handshake und das kann ich mir wohl zurechtbiegen. Wenn aber die Daten, die in einem Send() geschickt wurden, gemischt ankommen (nicht erst das Byte für den Record-Typ, sondern z.B. zuerst das Byte für die Spieler-ID), ist das ja völlig sinnlos, darum kann das eigentlich nicht sein, oder?

Ja, das mit dem "Client bewegt selbstständig, dann gibt es kein Ruckeln" werde ich auch beherzigen. Werde da gleich mal ein paar Experimente machen.

Erstmal danke an euch alle!


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:22 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz