📄 winmain.cpp
字号:
// List all players
ListPlayers();
return TRUE;
}
}
return FALSE; // Return failure
}
BOOL cApp::PlayerStateChange(sMessage *Msg)
{
sStateChangeMessage *scm, uscm;
long i, PlayerNum;
BOOL AllowChange;
float XDiff, ZDiff, Dist, Angle;
// Error checking
if(m_Players == NULL)
return FALSE;
// Get pointer to state change message
scm = (sStateChangeMessage*)Msg;
// Get player number in list
PlayerNum = -1;
for(i=0;i<MAX_PLAYERS;i++) {
if(m_Players[i].dpnidPlayer == Msg->Header.PlayerID && \
m_Players[i].Connected == TRUE) {
PlayerNum = i;
break;
}
}
if(PlayerNum == -1)
return FALSE;
AllowChange = TRUE; // Flag to allow changes in state
// Refuse to update player if swinging sword
if(m_Players[PlayerNum].State == STATE_SWING)
AllowChange = FALSE;
// Refuse to update player if hurt
if(m_Players[PlayerNum].State == STATE_HURT)
AllowChange = FALSE;
// Only change state if allowed
if(AllowChange == TRUE) {
// Update selected player
m_Players[PlayerNum].Time = timeGetTime();
m_Players[PlayerNum].State = scm->State;
m_Players[PlayerNum].Direction = scm->Direction;
// Adjust action time based on latency
m_Players[PlayerNum].Time -= m_Players[PlayerNum].Latency;
// Send player data to all clients
uscm.Header.Type = MSG_STATE_CHANGE;
uscm.Header.Size = sizeof(sStateChangeMessage);
uscm.Header.PlayerID = scm->Header.PlayerID;
uscm.State = m_Players[PlayerNum].State;
uscm.XPos = m_Players[PlayerNum].XPos;
uscm.YPos = m_Players[PlayerNum].YPos;
uscm.ZPos = m_Players[PlayerNum].ZPos;
uscm.Direction = m_Players[PlayerNum].Direction;
uscm.Speed = m_Players[PlayerNum].Speed;
SendNetworkMessage(&uscm, DPNSEND_NOLOOPBACK);
// If swinging sword, determine who's hurt
if(scm->State == STATE_SWING) {
// Check all players
for(i=0;i<MAX_PLAYERS;i++) {
// Only check against other players that are connected
if(i != PlayerNum && m_Players[i].Connected == TRUE) {
// Get distance to player
XDiff = (float)fabs(m_Players[PlayerNum].XPos - \
m_Players[i].XPos);
ZDiff = (float)fabs(m_Players[PlayerNum].ZPos - \
m_Players[i].ZPos);
Dist = XDiff*XDiff + ZDiff*ZDiff;
// Continue if distance between players acceptable
if(Dist < 10000.0f) {
// Get angle between players
Angle = -(float)atan2( \
(m_Players[i].ZPos - \
m_Players[PlayerNum].ZPos), \
(m_Players[i].XPos - \
m_Players[PlayerNum].XPos)) + \
1.570796f;
// Adjust for attacker's direction
Angle -= m_Players[PlayerNum].Direction;
Angle += 0.785f; // Adjust for FOV
// Bounds angle value
if(Angle < 0.0f)
Angle += 6.28f;
if(Angle >= 6.28f)
Angle -= 6.28f;
// Player hit if in front of attacker (90 FOV)
if(Angle >= 0.0f && Angle <= 1.570796f) {
// Set victim's state to hurt (if not already)
if(m_Players[i].State != STATE_HURT) {
m_Players[i].State = STATE_HURT;
m_Players[i].Time = timeGetTime();
// Send network message
uscm.Header.Type = MSG_STATE_CHANGE;
uscm.Header.Size = sizeof(sStateChangeMessage);
uscm.Header.PlayerID = m_Players[i].dpnidPlayer;
uscm.State = m_Players[i].State;
uscm.XPos = m_Players[i].XPos;
uscm.YPos = m_Players[i].YPos;
uscm.ZPos = m_Players[i].ZPos;
uscm.Direction = m_Players[i].Direction;
uscm.Speed = m_Players[i].Speed;
SendNetworkMessage(&uscm, DPNSEND_NOLOOPBACK);
}
}
}
}
}
}
}
return TRUE;
}
///////////////////////////////////////////////////////////
// App initialization functions
///////////////////////////////////////////////////////////
BOOL cApp::SelectAdapter()
{
int Result;
// Hide main window
ShowWindow(GethWnd(), SW_HIDE);
// Build a list of network adapters
m_Adapters.Init();
// Open configure dialog
Result = DialogBox(GethInst(), MAKEINTRESOURCE(IDD_CONFIG), \
GethWnd(), ConfigDialogProc);
// Don't continue if quit selected
if(Result == FALSE)
return FALSE;
// Continue if user selected OK
return TRUE;
}
void cApp::SetupApplicationWindow()
{
// Create the windows controls
// Window to hold host IP address
m_Controls[0] = CreateWindow("STATIC", "", \
WS_CHILD | WS_VISIBLE, \
4, 4, 312, 18, \
GethWnd(), NULL, GethInst(), NULL);
// Window to hold # of connected players
m_Controls[1] = CreateWindow("STATIC", \
"No Connected Players", \
WS_CHILD | WS_VISIBLE, \
4, 26, 312, 18, \
GethWnd(), NULL, GethInst(), NULL);
// List box to display connect player's names
m_Controls[2] = CreateWindow("LISTBOX", "", \
WS_CHILD | WS_BORDER | WS_VSCROLL | WS_VISIBLE, \
4, 48, 312, 154, \
GethWnd(), NULL, GethInst(), NULL);
// Show main window
ShowWindow(GethWnd(), SW_SHOW);
}
BOOL cApp::InitializeGame()
{
// Initialize the graphics device and set display mode
m_Graphics.Init();
m_Graphics.SetMode(GethWnd());
// Load the level mesh for collision checking
m_LevelMesh.Load(&m_Graphics, "..\\Data\\ArenaCM.x");
// Allocate message queue and reset message pointers
m_Messages = new sMessage[NUM_MESSAGES]();
m_MsgHead = m_MsgTail = 0;
// Create player structures
m_Players = new sPlayer[MAX_PLAYERS]();
// Reset # of players
m_NumPlayers = 0;
return TRUE;
}
BOOL cApp::HostGame()
{
char Text[33], IP[16];
// Configure server and begin hosting
m_Server.Init();
if(m_Server.Host(m_guidAdapter, 9123, \
"RPGGAME", NULL, MAX_PLAYERS) == FALSE)
return FALSE;
// Get Server IP address and display in application window
m_Server.GetIP(IP);
sprintf(Text, "Host IP Address: %s", IP);
SetWindowText(m_Controls[0], Text);
return TRUE; // Return success
}
///////////////////////////////////////////////////////////
// Game message queue processing and update functions
///////////////////////////////////////////////////////////
void cApp::ProcessQueuedMessages()
{
sMessage *Msg;
long Count = 0;
// Pull out messages to process
while(Count != MESSAGES_PER_FRAME && m_MsgHead != m_MsgTail) {
// Get pointer to 'tail' message
EnterCriticalSection(&m_MessageCS);
Msg = &m_Messages[m_MsgTail];
LeaveCriticalSection(&m_MessageCS);
// Process a single message based on type
switch(Msg->Header.Type) {
case MSG_ASSIGNID: // Send users their player ID
PlayerID(Msg, Msg->Header.PlayerID);
break;
case MSG_PLAYER_INFO: // Request player info
PlayerInfo(Msg, Msg->Header.PlayerID);
break;
case MSG_CREATE_PLAYER: // Add a player
AddPlayer(Msg);
break;
case MSG_DESTROY_PLAYER: // Remove a player
RemovePlayer(Msg);
break;
case MSG_STATE_CHANGE: // Change state of player
PlayerStateChange(Msg);
break;
}
Count++; // Increase processed message count
// Goto next message in list
EnterCriticalSection(&m_MessageCS);
m_MsgTail = (m_MsgTail + 1) % NUM_MESSAGES;
LeaveCriticalSection(&m_MessageCS);
}
}
void cApp::UpdatePlayers()
{
long i;
float XMove, ZMove, Speed;
sStateChangeMessage scm;
long Elapsed;
// Loop through all players
for(i=0;i<MAX_PLAYERS;i++) {
// Only update connected players
if(m_Players[i].Connected == TRUE) {
// Get elapsed time from now and state time
Elapsed = timeGetTime() - m_Players[i].Time;
// Process player movement state
if(m_Players[i].State == STATE_MOVE) {
// Calculate amount of movement by time passed
Speed = (float)Elapsed / 1000.0f * m_Players[i].Speed;
XMove = (float)sin(m_Players[i].Direction) * Speed;
ZMove = (float)cos(m_Players[i].Direction) * Speed;
// Check for movement collisions -
// can't walk past anything blocking path.
if(CheckIntersect(&m_LevelMesh, \
m_Players[i].XPos, \
m_Players[i].YPos + 16.0f, \
m_Players[i].ZPos, \
m_Players[i].XPos + XMove, \
m_Players[i].YPos + 16.0f, \
m_Players[i].ZPos + ZMove) == TRUE)
XMove = ZMove = 0.0f;
// Update player coordinates
m_Players[i].XPos += XMove;
m_Players[i].YPos = 0.0f; // Stay on ground
m_Players[i].ZPos += ZMove;
m_Players[i].Time = timeGetTime(); // Reset time
}
// Clear swing status after 1 second
if(m_Players[i].State == STATE_SWING) {
if(Elapsed > 1000) {
m_Players[i].State = STATE_IDLE;
// Send network message to player to clear
scm.Header.Type = MSG_STATE_CHANGE;
scm.Header.Size = sizeof(sStateChangeMessage);
scm.Header.PlayerID = m_Players[i].dpnidPlayer;
scm.XPos = m_Players[i].XPos;
scm.YPos = m_Players[i].YPos;
scm.ZPos = m_Players[i].ZPos;
scm.Direction = m_Players[i].Direction;
scm.Speed = m_Players[i].Speed;
scm.State = m_Players[i].State;
// Send the message over network
SendNetworkMessage(&scm, DPNSEND_NOLOOPBACK, -1);
}
}
// Clear hurt status after 1 second
if(m_Players[i].State == STATE_HURT) {
if(Elapsed > 1000) {
m_Players[i].State = STATE_IDLE;
// Send network message to player to clear
scm.Header.Type = MSG_STATE_CHANGE;
scm.Header.Size = sizeof(sStateChangeMessage);
scm.Header.PlayerID = m_Players[i].dpnidPlayer;
scm.XPos = m_Players[i].XPos;
scm.YPos = m_Players[i].YPos;
scm.ZPos = m_Players[i].ZPos;
scm.Direction = m_Players[i].Direction;
scm.Speed = m_Players[i].Speed;
scm.State = m_Players[i].State;
// Send the message over network
SendNetworkMessage(&scm, DPNSEND_NOLOOPBACK, -1);
}
}
}
}
}
void cApp::UpdateNetwork()
{
long i;
sStateChangeMessage scm;
// Send all player updates
for(i=0;i<MAX_PLAYERS;i++) {
// Only send data about connected players
if(m_Players[i].Connected == TRUE) {
scm.Header.Type = MSG_STATE_CHANGE;
scm.Header.Size = sizeof(sStateChangeMessage);
scm.Header.PlayerID = m_Players[i].dpnidPlayer;
scm.XPos = m_Players[i].XPos;
scm.YPos = m_Players[i].YPos;
scm.ZPos = m_Players[i].ZPos;
scm.Direction = m_Players[i].Direction;
scm.Speed = m_Players[i].Speed;
scm.State = m_Players[i].State;
scm.Latency = m_Players[i].Latency;
// Send the message over network
SendNetworkMessage(&scm, DPNSEND_NOLOOPBACK);
}
}
}
void cApp::UpdateLatency()
{
long i;
DPN_CONNECTION_INFO dpci;
HRESULT hr;
// Go through all players
for(i=0;i<MAX_PLAYERS;i++) {
// Only process connected players
if(m_Players[i].Connected == TRUE) {
// Request player connection settings
hr = m_Server.GetServerCOM()->GetConnectionInfo( \
m_Players[i].dpnidPlayer, &dpci, 0);
if(SUCCEEDED(hr)) {
m_Players[i].Latency = dpci.dwRoundTripLatencyMS / 2;
// Bounds latency to 1 second
if(m_Players[i].Latency > 1000)
m_Players[i].Latency = 1000;
} else {
m_Players[i].Latency = 0;
}
}
}
}
///////////////////////////////////////////////////////////
// Game logic functions
///////////////////////////////////////////////////////////
BOOL cApp::CheckIntersect(cMesh *Mesh, \
float XStart, float YStart, float ZStart, \
float XEnd, float YEnd, float ZEnd)
{
sMesh *MeshPtr;
BOOL Hit;
float u, v, Dist;
float XDiff, YDiff, ZDiff, Size;
DWORD FaceIndex;
D3DXVECTOR3 vecDir;
// Error checking
if(Mesh == NULL)
return FALSE;
// Start with parent mesh
if((MeshPtr = Mesh->GetParentMesh()) == NULL)
return FALSE;
// Calculate ray
XDiff = XEnd - XStart;
YDiff = YEnd - YStart;
ZDiff = ZEnd - ZStart;
D3DXVec3Normalize(&vecDir, &D3DXVECTOR3(XDiff, YDiff, ZDiff));
// Go through each mesh looking for intersection
while(MeshPtr != NULL) {
D3DXIntersect(MeshPtr->m_Mesh, \
&D3DXVECTOR3(XStart,YStart,ZStart), &vecDir, \
&Hit, &FaceIndex, &u, &v, &Dist);
if(Hit == TRUE) {
Size = (float)sqrt(XDiff*XDiff+YDiff*YDiff+ZDiff*ZDiff);
if(Dist <= Size)
return TRUE;
}
MeshPtr = MeshPtr->m_Next;
}
return FALSE;
}
///////////////////////////////////////////////////////////
// Server class code
///////////////////////////////////////////////////////////
BOOL cServer::CreatePlayer(DPNMSG_CREATE_PLAYER *Msg)
{
// Send message to application class instance (if any)
if(g_Application != NULL)
g_Application->CreatePlayer(Msg);
return TRUE;
}
BOOL cServer::DestroyPlayer(DPNMSG_DESTROY_PLAYER *Msg)
{
// Send message to application class instance (if any)
if(g_Application != NULL)
g_Application->DestroyPlayer(Msg);
return TRUE;
}
BOOL cServer::Receive(DPNMSG_RECEIVE *Msg)
{
// Send message to application class instance (if any)
if(g_Application != NULL)
g_Application->Receive(Msg);
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -