📄 winmain.cpp
字号:
/**************************************************
WinMain.cpp
Chapter 19 Multiplayer Client Demo
Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)
Required libraries:
D3D8.LIB, D3DX8.LIB, DINPUT8.LIB, D3DXOF.LIB,
DXGUID.LIB, DPNET.LIB, DPLAY.LIB, and DPNADDR.LIB
**************************************************/
#include "Core_Global.h"
#include "Frustum.h"
#include "NodeTree.h"
#include "WinMain.h"
#include "resource.h"
cApp *g_Application; // Global application pointer
cNetworkAdapter *g_Adapters; // Global adapter list pointer
BOOL g_Connected = FALSE; // Connection status
///////////////////////////////////////////////////////////
// cApp functions
///////////////////////////////////////////////////////////
cApp::cApp()
{
// Setup main window information
m_Width = 640;
m_Height = 480;
m_Style = WS_BORDER | WS_CAPTION | \
WS_MINIMIZEBOX | WS_SYSMENU;
strcpy(m_Class, "ClientClass");
strcpy(m_Caption, "Network Client Demo by Jim Adams");
// Clear class data
m_Players = NULL;
g_Application = this;
g_Adapters = &m_Adapters;
// Create a critical section for updating data
InitializeCriticalSection(&m_UpdateCS);
}
BOOL cApp::Init()
{
// Select a network adapter to use (or quit if selected)
if(SelectAdapter() == FALSE)
return FALSE;
// Initialize the game, set video mode, load data, etc
if(InitializeGame() == FALSE) {
Error(FALSE, "Unable to initialize game.");
return FALSE;
}
// Join networked game
if(JoinGame() == FALSE) {
Error(FALSE, "Unable to connect to server.");
return FALSE;
}
return TRUE;
}
BOOL cApp::Shutdown()
{
// Shutdown network
m_Adapters.Shutdown();
m_Client.Disconnect();
m_Client.Shutdown();
// Free players
delete [] m_Players;
m_Players = NULL;
// Free meshes
m_NodeTreeMesh.Free();
m_TerrainMesh.Free();
m_CharacterMesh.Free();
m_WeaponMesh.Free();
m_CharacterAnim.Free();
// Shutdown input
m_Keyboard.Free();
m_Mouse.Free();
m_Input.Shutdown();
// Shutdown graphics
m_Font.Free();
m_Graphics.Shutdown();
// Remove critical section
DeleteCriticalSection(&m_UpdateCS);
return TRUE;
}
BOOL cApp::Frame()
{
static DWORD UpdateCounter = timeGetTime();
static long MoveAction = 0, LastMove = 0;
static BOOL CamMoved = FALSE;
BOOL AllowMovement;
long Dir;
float Angles[13] = { 0.0f, 0.0f, 1.57f, 0.785f, 3.14f, \
0.0f, 2.355f, 0.0f, 4.71f, 5.495f, \
0.0f, 0.0f, 3.925f };
// Get local input every frame
m_Keyboard.Acquire(TRUE);
m_Mouse.Acquire(TRUE);
m_Keyboard.Read();
m_Mouse.Read();
// Pressing ESC quits program
if(m_Keyboard.GetKeyState(KEY_ESC) == TRUE)
return FALSE;
// Handle connection and waiting for data screen
if(g_Connected == FALSE || !m_Players[0].dpnidPlayer) {
// Display message(s)
m_Graphics.Clear();
if(m_Graphics.BeginScene() == TRUE) {
m_Font.Print("Connecting to server...", 0, 0);
if(!m_Players[0].dpnidPlayer)
m_Font.Print("Waiting for server data...", 0, 20);
m_Graphics.EndScene();
}
m_Graphics.Display();
// Request player ID from server every 2 seconds
if(timeGetTime() > UpdateCounter + 2000) {
UpdateCounter = timeGetTime(); // Update counter
sAssignPlayerIDMessage apidm;
apidm.Header.Type = MSG_ASSIGNID;
apidm.Header.Size = sizeof(sAssignPlayerIDMessage);
SendNetworkMessage(&apidm, DPNSEND_NOLOOPBACK | \
DPNSEND_GUARANTEED);
}
return TRUE;
}
// Store movements every frame
if(m_Keyboard.GetKeyState(KEY_UP) == TRUE)
MoveAction |= 1;
if(m_Keyboard.GetKeyState(KEY_RIGHT) == TRUE)
MoveAction |= 2;
if(m_Keyboard.GetKeyState(KEY_DOWN) == TRUE)
MoveAction |= 4;
if(m_Keyboard.GetKeyState(KEY_LEFT) == TRUE)
MoveAction |= 8;
// Store attack action
if(m_Keyboard.GetKeyState(KEY_SPACE) == TRUE)
MoveAction |= 16;
if(m_Mouse.GetButtonState(MOUSE_LBUTTON) == TRUE)
MoveAction |= 16;
// Rotate camera
if(m_Mouse.GetXDelta() > 0) {
m_CamAngle -= 0.1f;
CamMoved = TRUE;
}
if(m_Mouse.GetXDelta() < 0) {
m_CamAngle += 0.1f;
CamMoved = TRUE;
}
// Only update players every 33ms (30 times a second)
if(timeGetTime() < UpdateCounter + 33)
return TRUE;
// Set flag to allow player movement
AllowMovement = TRUE;
// Don't allow movement if still swinging weapon
if(m_Players[0].State == STATE_SWING)
AllowMovement = FALSE;
// Don't allow movement if still being hurt
if(m_Players[0].State == STATE_HURT)
AllowMovement = FALSE;
// Handle movements if allowed
if(AllowMovement == TRUE) {
// Process attack
if(MoveAction & 16) {
MoveAction = 0; // Clear movement
LastMove = 0; // Clear last movement
// Send attack message - let server signal swing
sStateChangeMessage Msg;
Msg.Header.Type = MSG_STATE_CHANGE;
Msg.Header.Size = sizeof(sStateChangeMessage);
Msg.Header.PlayerID = m_Players[0].dpnidPlayer;
Msg.State = STATE_SWING;
Msg.Direction = m_Players[0].Direction;
// Send message to server
SendNetworkMessage(&Msg, DPNSEND_NOLOOPBACK);
}
// Process local player movements
if((Dir = MoveAction) > 0 && Dir < 13) {
// Set new player state (w/time and direction)
EnterCriticalSection(&m_UpdateCS);
m_Players[0].State = STATE_MOVE;
m_Players[0].Direction = Angles[Dir] - m_CamAngle + 4.71f;
LeaveCriticalSection(&m_UpdateCS);
// Reset last move if camera moved since last update
if(CamMoved == TRUE) {
CamMoved = FALSE;
LastMove = 0;
}
// Send actions to server if changed from last move
if(MoveAction != LastMove) {
LastMove = MoveAction; // Store last action
m_Players[0].Time = timeGetTime();
// Construct message
sStateChangeMessage Msg;
Msg.Header.Type = MSG_STATE_CHANGE;
Msg.Header.Size = sizeof(sStateChangeMessage);
Msg.Header.PlayerID = m_Players[0].dpnidPlayer;
Msg.State = STATE_MOVE;
Msg.Direction = m_Players[0].Direction;
// Send message to server
SendNetworkMessage(&Msg, DPNSEND_NOLOOPBACK);
}
} else {
// Change to idle state
EnterCriticalSection(&m_UpdateCS);
m_Players[0].State = STATE_IDLE;
LeaveCriticalSection(&m_UpdateCS);
// Send update only if player moved last update
if(LastMove) {
LastMove = 0;
sStateChangeMessage Msg;
Msg.Header.Type = MSG_STATE_CHANGE;
Msg.Header.Size = sizeof(sStateChangeMessage);
Msg.Header.PlayerID = m_Players[0].dpnidPlayer;
Msg.State = STATE_IDLE;
Msg.Direction = m_Players[0].Direction;
// Send message to server
SendNetworkMessage(&Msg, DPNSEND_NOLOOPBACK);
}
}
}
// Update all players
UpdatePlayers();
// Render the scene
RenderScene();
MoveAction = 0; // Clear action data for next frame
UpdateCounter = timeGetTime(); // Reset update counter
return TRUE;
}
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, \
LPSTR szCmdLine, int nCmdShow)
{
cApp App;
return App.Run();
}
///////////////////////////////////////////////////////////
// Select adapter dialog and other functions
///////////////////////////////////////////////////////////
BOOL CALLBACK ConnectDialogProc(HWND hWnd, UINT uMsg, \
WPARAM wParam, LPARAM lParam)
{
int Selection;
long i;
char Name[32], IP[16], Text[256];
static HWND hAdapters;
switch(uMsg) {
case WM_INITDIALOG:
// Get adapter list window handle
hAdapters = GetDlgItem(hWnd, IDC_ADAPTERS);
// Add adapter names to list
for(i=0;i<g_Adapters->GetNumAdapters();i++) {
g_Adapters->GetName(i, Text);
SendMessage(hAdapters, CB_INSERTSTRING,i,(LPARAM)Text);
}
// Select first adapter in list
SendMessage(hAdapters, CB_SETCURSEL, 0, 0);
// Clear fields
SetWindowText(GetDlgItem(hWnd, IDC_HOSTIP), "127.0.0.1");
SetWindowText(GetDlgItem(hWnd, IDC_NAME), "");
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDC_OK:
// Make sure an adapter was selected
if((Selection = SendMessage(hAdapters, \
CB_GETCURSEL, \
0, 0)) == LB_ERR)
break;
// Make sure there's an IP entered
GetWindowText(GetDlgItem(hWnd, IDC_HOSTIP), IP, 16);
if(!strlen(IP))
break;
// Make sure there's a name entered
GetWindowText(GetDlgItem(hWnd, IDC_NAME), Name, 32);
if(!strlen(Name))
break;
// Assign Adapter, IP, and Name
if(g_Application != NULL)
g_Application->SetInfo( \
g_Adapters->GetGUID(Selection), IP, Name);
// Quit dialog
EndDialog(hWnd, TRUE);
return TRUE;
case IDC_CANCEL:
EndDialog(hWnd, FALSE);
return TRUE;
}
}
return FALSE;
}
void cApp::SetInfo(GUID *Adapter, char *IP, char *Name)
{
m_guidAdapter = Adapter;
strcpy(m_HostIP, IP);
strcpy(m_Name, Name);
}
///////////////////////////////////////////////////////////
// Misc. application functions
///////////////////////////////////////////////////////////
long cApp::GetPlayerNum(DPNID dpnidPlayer)
{
long i;
// Error checking
if(m_Players == NULL)
return -1;
// Scan list looking for match
for(i=0;i<MAX_PLAYERS;i++) {
if(m_Players[i].dpnidPlayer == dpnidPlayer && \
m_Players[i].Connected == TRUE)
return i;
}
return -1; // Not found in list
}
///////////////////////////////////////////////////////////
// Network send and receive functions
///////////////////////////////////////////////////////////
BOOL cApp::SendNetworkMessage(void *Msg, long SendFlags)
{
sMessageHeader *mh = (sMessageHeader*)Msg;
unsigned long Size;
// Get size of message to send
if((Size = mh->Size) == 0)
return FALSE;
// Send the mesage
return m_Client.Send(Msg, Size, SendFlags);
}
BOOL cApp::Receive(DPNMSG_RECEIVE *Msg)
{
sMessage *MsgPtr;
// Get pointer to received data
MsgPtr = (sMessage*)Msg->pReceiveData;
// Handle packets by type
switch(MsgPtr->Header.Type) {
case MSG_ASSIGNID: // Assign local player ID
AssignID(MsgPtr);
break;
case MSG_PLAYER_INFO: // Add a player to list
case MSG_CREATE_PLAYER:
CreatePlayer(MsgPtr);
break;
case MSG_DESTROY_PLAYER: // Remove a player from list
DestroyPlayer(MsgPtr);
break;
case MSG_STATE_CHANGE: // Change state of player
ChangeState(MsgPtr);
break;
}
return TRUE;
}
///////////////////////////////////////////////////////////
// Message parsing functions
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -