BlitzBasic-Community-Tutorial/ Multiplayer

Netzwerkprogrammierung gehört zu den komplexeren Gebieten der Spieleentwicklung. Dies liegt hauptsächlich daran, dass, sobald man damit beginnt, die Fehlerzahl und -komplexität immens zunimmt. Bei den meisten Fehlern im Netzwerkbereich ist standardmäßiges Debuggen quasi sinnlos oder gar nicht möglich, da beim Debuggen das Programm angehalten werden muss, während die Gegenstelle noch munter weiterläuft, was leicht Timeouts usw. auslösen kann. Zusätzlich erfordert fortgeschrittenes Netzwerkprogrammieren eine neue Sichtweise. Das Spiel läuf im Mehrspielermodus nicht mehr einfach linear ab. Im Einzelspielermodus weiß man immer, dass man alle nötigen Daten und Informationen über das Spielgeschehen hat. Im Mehrspielermodus kann es passieren, dass irgendwelche Informationen fehlen, wenn sie dringend gebraucht werden.

UDP, TCP oder DirectPlay?

Bearbeiten

Eine große Frage, die sich jedem stellt, der ein neues Netzwerkspiel schreiben will, ist, auf welcher Protokollbasis es aufgebaut sein soll. Blitzbasic unterstützt standardmäßig 3 verschiedene Arten. DirectPlay, TCP und UDP. Im Gegensatz zu TCP und UDP, die als Protokolle bezeichnet werden, ist DirectPlay eine Engine, die zu Microsofts DirectX gehört. Diese unterstützt schon von Grunde auf TCP, UDP, Seriell und IPX. Der Programmierer muss sich nicht direkt mit den Protokollen befassen, da das von DirectPlay gehandhabt wird. Dies macht DirectPlay vor allem für Anfänger interessant, da es mit Abstand der leichteste Weg ist, ein Netzwerkspiel/Applikation zu verwirklichen. Für fortgeschrittene Netzwerkprogrammierer ist es allerdings zu unflexibel und hat auch andere Nachteile. Es ist langsamer, als wenn man direkt mit TCP oder UDP arbeitet und es braucht eine Menge an Ports, was störend ist wenn man im Internet hosten will. TCP steht für "Transmission Control Protocol". Es ist ein Verbindungsorientiertes Protokoll, das heißt, dass immer eine stehende Leitung (Stream) aufgebaut wird. Dadurch wird es Router und Firewall freundlicher und man braucht außer als Host selten eine spezielle Anpassung. Außerdem wird durch die feste Verbindung auch garantiert, dass alle Pakete, die man losschickt, auch sicher und in der selben Reihenfolge ankommen. Dies hat allerdings auch seinen Preis. Die Latenzzeit von TCP ist ungefähr 3-mal so lang wie die bei UDP. UDP steht für User Datagram Protocol. Es ist im Gegensatz zu TCP ein Verbindungsloses Protokoll, was es einerseits schneller macht als TCP, aber auch mehr Probleme mit Routern und Firewalls auslöst. Zusätzlich ist bei UDP nicht garantiert, dass Pakete auch wirklich ankommen.

Auch wenn TCP mit nur 8 und UDP mit 9 Befehlen nach wenig Stoff aussieht, ist es trotzdem für Anfänger empfehlenswert mit DirectPlay anzufangen. Die 8/9 Befehle sind zwar leicht auswendig gelernt aber die Anwendung jener ist vergleichsweise viel komplizierter, als die von DirectPlay. Wenn man DirectPlay nicht verwenden will, muss man sich entscheiden auf welchem Protokoll man sein Spiel aufbauen will. TCP ist aber generell UDP vorzuziehen da UDP außer Geschwindigkeit keine Vorteile sondern nur Nachteile bringt. Aber in manchen Spielegenren (Egoshootern und andere Actionspiele) wird diese Geschwindigkeit benötigt. Dann sollten beide Protokolle parallel benutzt werden. Wenn es aber möglich ist nur TCP zu verwenden, dann sollte dies aber auch getan werden.

DirectPlay

Bearbeiten

Wie oben schon erwähnt wurde, ist UDP(User Datagram Protocol) am besten für Schnelle Genres geeignet. Da wir uns noch in der 2.ten Dimension befinden, dient uns als Beispielprogramm das eben gecodete Pong Spiel. Aber erstmal die Grundbefehle: Die wichtigsten UDP Befehle sind natürlich folgende:

CreateUdpStream()
CloseUDPStream()
RecvUDPMsg()
SendUDPMsg()
;Sämtliche Read & Write Befehle 


stream = CreateUDPStream( [portnum%] )

Mit CreateUDPStream erstellt man einen UDP Stream über den optionalen, als Parameter, angegebenen Port. Wenn man keinen Port angibt, sucht sich BlitzBasic automatisch einen freien Port, den man mit dem Befehl UdpStreamPort() rausfinden kann. Der Rückgabewert stream liefert die Indendität des erstellten Streams in einem Integer Wert zurück. Falls er 0 zurückliefert, konnte die Netzwerkverbindung nicht erstellt werden.

CloseUDPStream( stream )

Mit dem Befehl CloseUDPStream schliesst man einen UDP Stream , der zuvor mit CreateUDPStream geöffnet wurde. Der Parameter stream ist die Indendität des Streams.

RecvUDPMsg()

Allgemein

Bearbeiten

Das Transmission Control Protocol (TCP) (zu dt. Übertragungssteuerungsprotokoll) ist vor allem für rundenbasierte (also nicht actionlastige) Spiele geeignet, da es nicht ganz so schnell wie das UDP Protokoll ist. Der Vorteil in TCP liegt daran das alle Daten auch an kommen, und nicht wie bei UDP verloren gehen können. Solte ein Datenpacket nicht den Clienten erreichen, wird dieses automatisch nocheinmal gesendet.

Alle TCP-Befehle in der Übersicht:

CreateTCPServer( [port] ) Dieser Befehl wird benötigt, um einen Server zu erstellen, zu den Verbindungen hergestellt werden können. Der Rückgabewert ist ein Integer, der benötigt wird, um fest zu stellen, ob eine Verbindung hergestellt wurde. Wird kein Port angegeben, sucht sie BB den 1. freinen Port selbst. Ich empfehle euch einen port der über 5000 liegt, damit ihr keine anderen Prozesse stört! Wird eine 0 zurück geliefert, konte der Server nicht erstellt werden, das kann folgende gründe haben: -der Port ist blockiert -eine Firewall blockiert den Port, oder das Programm

CloseTCPServer( server ) Dieser Befehl schließt beendet einen Server wieder. Es kommt zu einem fehler, solltet ihr einen falschen wert übergeben. Achtung: der Befehl setzt die Variable nicht wieder auf 0, das müsst ihr selbst machen. Ich empfehle diese Funktion zu verwenden:

Function New_CloseTCPServer( server )
  If server=0 then Return(server)
  CloseTCPServer(server)
  server=0
  Return(server)
End Function

Diese Funktion prüft ob der Server bereits geschlossen wurde, um einen Fehler zu vermeiden. Außdem setzt es die Server Variable wieder auf 0 Ihr solltet die Funktion wie folgt verwenden:

Local tcp_server=CreateTCPServer(8080)
tcp_server=New_CloseTCPSServer(tcp_server)

Function New_CloseTCPServer( server )
  If server=0 then Return(server)
  CloseTCPServer(server)
  server=0
  Return(server)
End Function