Platform SDK: DirectX |
This tutorial pertains only to applications written in Visual Basic. See DirectPlay C/C++ Tutorials
DirectPlay starts sending messages as soon as at least one player has joined the session. Each time a player joins or leaves the session, a system message is sent. In the Memory sample, this message triggers an update of the list of players in frmWaiting.
The manner in which the game (or other form of DirectPlay session) starts is entirely up to the application. As far as DirectPlay is concerned, a session is just a session, whether or not the application is sending messages to update the game state.
The Memory sample gives the host an opportunity to start the game when at least one other player has joined. When the host clicks the Start button, the application first disables joining so that the session is no longer available to new players:
Set SessionData = gObjDPlay.CreateSessionData Call gObjDPlay.GetSessionDesc(SessionData) Call SessionData.SetFlags(SessionData.GetFlags + _ DPSESSION_JOINDISABLED) Call gObjDPlay.SetSessionDesc(SessionData)
The application then generates a message that contains a type identifier, a list of the player IDs in the order in which they will play, and the arrangement of the tiles on the game board. In response to this message, other instances of the application update their information about the play order and game board. This message is an example of how players exchange information about the game state.
Data is first packed into the message by using the various write methods of DirectPlayMessage:
Dim dpMsg As DirectPlayMessage Set dpMsg = gObjDPlay.CreateMessage ' Pack message type Call dpMsg.WriteLong(MSG_SETUPBOARD) ' Pack number of players Call dpMsg.WriteByte(gNumPlayers) ' Pack player IDs. Dim PlayerID As Long For X = 0 To gNumPlayers - 1 PlayerID = objDPEnumPlayers.GetDPID(X + 1) dpMsg.WriteLong (PlayerID) ' Keep local copy of player IDs gPlayerIDs(X) = PlayerID ' Assign place in play order to the host If PlayerID = gMyPlayerID Then gMyTurn = X Next X ' Pack tile arrangement For X = 0 To NumCells - 1 dpMsg.WriteByte (gPicArray(X)) Next X
Note that the host application instance needs to update its own game state here. An application instance doesn't receive any of the messages it sends, so this is the host's last chance to perform the updating that other instances will perform when they receive the message.
The application now sends the message to all the other players, using the DPSEND_GUARANTEED flag because it is essential that all other players receive this information. (Nonguaranteed messages would be appropriate for small changes in the state of a fast-moving action game.)
Call gObjDPlay.Send(gMyPlayerID, DPID_ALLPLAYERS, _ DPSEND_GUARANTEED, dpMsg)
At the receiving end, the application looks for messages in the Sub Main procedure, relying on DoEvents to let other things happen while polling:
Do While DoEvents() GetDPMessages Loop
In the GetDPMessages procedure, the application checks to see how many messages are pending:
Dim MsgCount As Long MsgCount = gObjDPlay.GetMessageCount(gMyPlayerID)
It then retrieves each message in turn, encapsulating it in the DirectPlayMessage object dpMsg. It extracts the message type, which is always the first Long both in system messages and in messages defined by Memory.
Dim FromPlayerID As Long Dim ToPlayerID As Long Dim dpMsg As DirectPlayMessage Dim MsgType As Long ' Some other declarations omitted; see GlobalModule.bas . . . Do While MsgCount > 0 Set dpMsg = gObjDPlay.Receive(FromPlayerID, ToPlayerID, _ DPRECEIVE_ALL) MsgType = dpMsg.ReadLong() MsgCount = MsgCount - 1
System messages are identified by DPSYS_MESSAGE in FromPlayerID. All others are application-defined. When Memory finds an application-defined message of type MSG_SETUPBOARD, it reads out the data in the same order as it was put in, and does a few more things to update the game state and allow play to begin:
Select Case MsgType Case MSG_SETUPBOARD ' Number of players gNumPlayers = dpMsg.ReadByte ' Play IDs, in play order. Unused players have ID of 0. For X = 0 To gNumPlayers - 1 gPlayerIDs(X) = dpMsg.ReadLong If gPlayerIDs(X) = gMyPlayerID Then gMyTurn = X Next X ' Tile arrangement For X = 0 To NumCells - 1 gPicArray(X) = dpMsg.ReadByte Next X ' Show the game board. frmWaiting.Hide gGameUnderway = True frmGameBoard.Show . . . End Select . . . Loop