ATTENTION READERS! Lucky's VB Gaming Site is no longer active. For updated game programming information and tutorials, please visit The Game Programming Wiki!
Nachrichten während des Spieles verschicken
Vegetarier wegschauen. Wir werden uns jetzt mit den Eingeweiden von
DPlay beschäftigen: Nachrichten. Das ist nichts für jemanden
mit schwachem Herz! Holt eure Kochtöpfe, wir kochen uns einen schönen
Eintopf saftigen Codes!
Mhm.... DirectPlay Suppe.
(okok... zugegeben, die Übersetzung ist ein bißchen... "strange"
;-) - d.Ü.)
Es gibt zwei Arten von Nachrichten, die uns begegnen werden, zum einen
"benutzerdefinierte" Nachrichten und "system" Nachrichten. Eine benutzerdefinierte
Nachricht müssen wir selbst erstellen, um spielrelevante Informationen
zwischen den Spielern auszutauschen. Eine system Nachricht erstellt DPlay
selbst, um die anderen DPlay -Objekte aktuell zu halten.
Beispiel: Wir benutzen eine benutzerdefinierte Nachricht um die Bewegung
des Balles an die zwei Spieler eines Spieles von NetPONG zu übermitteln.
Eine Systemnachricht informiert den Host z.B. darüber, daß
dem Spiel ein neuer Spieler beigetreten ist.
Systemnachrichten werden von DPlay automatisch zu geeigneten Zeitpunkten
gesendet, die benutzerdefinierten können wir aber senden wann immer
wir wollen:
Const MSG_CHATTEXT = 0
Dim dpMsg As DirectPlayMessage 'Create a message object
Set dpMsg = dp.CreateMessage
dpMsg.WriteLong MSG_CHATTEXT
dpMsg.WriteString strChatText
dp.SendEx lngPlayerID, DPID_ALLPLAYERS, DPSEND_GUARANTEED, dpMsg, 0, 0, 0
Gib das DirectPlayMessage Objekt ein. Initialisiere ein neues mit
der Methode
DirectPlay4.CreateMessage und dann kann es los gehen.
. DirectPlayMessage-Objekte stellen Methoden zur Verfügung,
die uns erlauben, Daten verschiedener Arten zu "schreiben" (Long, Integers,
Strings, etc.). Im oben gezeigten Code schreiben wir zuerst eine Long-Variable
MSG_CHATTEXT. Es ist üblich, am Anfang einer Nachricht ein Long zu
schreiben, die die Art der Nachricht angibt (du mußt diese Konstanten
selbst erstellen und festsetzen!), um sie so sortieren und unterschiedlich
behandeln zu können, wie du später sehen wirst. Nachdem wir die
Art der Nachricht geschrieben haben, können wir weitergehen und die
Nachricht mit unseren gewünschten Daten füllen. In diesem Fall
senden wir einen Textnachricht, die wir z.B. für eine Kommunikation
von Spieler zu Spieler während des Spieles benutzen können. Wir
nehmen an, das "strChatText" die Zeichenfolge enthält, die wir verschicken
wollen.
Die DirectPlay4.SendEx Methode wird genutzt, um das Nachrichten-Objekt
zu versenden nachdem wir es mit Informationen gefüllt haben. Das erste
Parameter dieser Methode ist die "Spieler-ID" (erinnerst du dich? Wir haben
sie gespeichert als wir den Spieler erstellt haben!). Das zweite, an welche(n)
Spieler wir die Nachricht senden wollen. Wir können hier jeden beliebigen
Spieler angeben (oder eine Gruppe... siehe SDK) oder die DPID_ALLPLAYER-Konstante
benutzen, damit die Nachricht an jeden Spieler gesendet wird.
Durch das dritte Parameter legen wir die Eigenschaften fest, die wir
beim Senden berücksichtigen wollen. Da gibt es ziemlich viele, inklusive
DPSEND_ENCRYPT und DPSEND_SIGNED, aber meistens benutzen wir DPSEND_GUARANTEED
und DPSEND_ASYNC. Benutze DPSEND_GUARANTEED wenn die Nachricht auf jeden
Fall ankommen muss, DPSEND_ASYNC wenn die Nachricht nicht überlebenswichtig
ist, und vielleicht durch nachfolgende Nachrichten ihre Gültigkeit
verliert.
Wenn der Host z.B. ein Spiel startetn, sollten "GUARANTEED" (garantierte)
Nachrichten an alle Spieler gesendet werden, weil es absolut notwendig
ist, daß sie diese Information erhalten. Einmal im Spiel selbst,
wird häufig viel überflüssige Information gesendet. In einem
Spiel wie StarCraft (oder anderen Echtzeit-Strategiespielen) führt
der Verlust einer Nachricht, die eine Truppenposition enthält, zu
keinen schwerwiegenden Folgen, da die nächste Nachricht sowieso die
nächst-neuere Position enthält und die erste Nachricht sowieso
überholt wäre. In solchen Situationen ist es vorteilhaft Nachrichten
asynchron zu senden, da sie so schneller und in einer Art "schnellfeuer
Modus" gesendet werden können.
Das vierte Parameter, das die Methode DirectPlay4.SendEx enthält,
muss das DirectPlayMessage - Objekt sein, das wir senden wollen.
Das fünfte, sechste und siebte Parameter werden für Priorität,
Zeitlimit und Kontext verwendet. Sie werden hier nicht besprochen. Das
wäre einfach zu viel Stoff um es alles durchzukauen!
So, jetzt weißt du wie man eine Nachricht erstellt und sendet.
Es erscheint logisch, zu lernen wie man die Nachricht empfängt und
auswertet!
Dim lngFromPlayerID As Long
Dim lngToPlayerID As Long
Dim lngMsgType As Long
Dim dpMsg As DirectPlayMessage
Dim lngMsgCount As Long
lngMsgCount = dp.GetMessageCount(lngPlayerID)
Do While lngMsgCount > 0
Set dpMsg = dp.Receive(lngFromPlayerID, lngToPlayerID, DPRECEIVE_ALL)
lngMsgType = dpMsg.ReadLong()
lngMsgCount = lngMsgCount - 1
Zuerst rufen wir die Methode DirectPlay4.GetMessageCount um die
Zahl der Nachrichten zu erhalten, die eingetroffen sind und nun auf uns
warten. Wir müssen die Spieler-ID an die Funktion GetMessageCount
übergeben, damit DPlay weiß, für welchen Spieler wir die
Nachrichten abfragen (ja, es kann mehr als ein Spieler zur gleichen Zeit
aktiv sein!).
Als nächstes verarbeiten wir nacheinander alle Nachrichten. Wir
erstellen ein neues DirectPlayMessage - Objekt und initiieren es
mit der Methode DirectPlay4.Receive die die nächste Nachricht
in der Warteschlange abruft.
Die Methode Receive gibt neben dem DirectPlayMessage zusätzlich
einige andere Daten zurück. Wenn wir ihm ein paar Long-Variablen übergeben,
gibt es die Spieler-ID des Senders als auch die Spieler-ID des Empfängers.
Das dritte Parameter, die Flags für Empfang, geben uns die Möglichkeit,
festzulegen, welche Nachrichten wir empfangen möchten. Übergeben
wir die DPRECEIVE_ALL Flag, heißt das, wir wollen JEDE Nachricht
empfangen. Mit anderen Konstanten können wir z.B. festlegen, daß
wir nur Nachrichten von einem bestimmten Spieler empfangen möchten
(z.B. der Wert des ersten Parameters) oder nur Nachrichten die zu einem
bestimmten Spieler gesendet wurden (zweites Parameter).
Haben wir das neue Nachrichtenobjekt erhalten, können wir den ersten
Long-Wert extrahieren. Dieser Wert sollte den Nachrichtentyp enthalten,
wie weiter oben beschrieben. Der Wert MSG_CHATTEXT zeigt uns dann z.B.
an, daß die Nachricht als Textnachricht geplant war, weil die Konstante
vorher für diesen Zweck definiert wurde.
Außerdem müssen wir den Nachrichtenzähler um Eins verringern,
so daß wir nur so oft Abfragen, wie auch Nachrichten zur Verarbeitung
da sind.
Jetzt, da wir alle diese Informationen dieser Nachricht haben, können
wir sie verarbeiten/auswerten. Als erstes müssen wir zwischen benutzerdefinierten
und Systemnachrichten unterscheiden:
If
lngFromPlayerID = DPID_SYSMSG Then
'...handle
system messages...
Else
'...handle
user-defined messages...
End If
Die Variable "lngFromPlayerID" enthält nun die Spieler-ID des Senders
der Nachricht. Dieser Wert ist gleich der Konstanten DPID_SYSMSG wenn die
Nachricht NICHT benutzerdefiniert ist. Wir benutzen daher die IF Anweisung,
um Systemnachrichten zu verarbeiten, und ELSE um alle anderen Werte abzudecken
- also die benuterdefinierten Nachrichten.
Als nächstes Unterscheiden wir die Nachrichten nach ihrem ersten
Long-Wert (der Nachrichtentyp). Eine "Select Case" Anweisung ist ideal
dafür:
Select Case lngMsgType
Case DPSYS_DESTROYPLAYERORGROUP, DPSYS_CREATEPLAYERORGROUP
'...a new player has joined/left the session, take action...
End Select
Hier behandekn wir zwei Arten von möglichen Systemnachrichten. Wenn
eine Spieler einem Spiel zusteigt oder es verläßt, werden diese
Anweisungen ausgeführt. Wir können dann Schritte einleiten, um
seine Erscheinung festzulegen (z.B. "Spielername - Ausgestiegen" o.ä.
- d.Ü.)
Select Case lngMsgType
Case MSG_CHATTEXT
'...we have receive chat text, take action...
strChatText = dpMsg.ReadString()
End Select
Hier sehen wir die Behandlung einer benutzerdefinierten Nachricht. Wenn
wir erstmal wissen, daß es sich um eine Textnachricht handelt, klnnen
wir die Zeichenfolge extrahieren. Diese kann in einer Zeichenfolge gespeichert
werden (hier benutzen wir eine vorherdefinierte String-Variable, "strChatText")
und können sie weiterverwenden.
:)
Das ist es! Was wir noch machen müssen ist DirectPlay beenden wenn
wir das Programm beenden!