📄 game.cpp
字号:
*/
cNM_LoginRequest req( m_localPlayerName );
SendToServerR( req );
DebPrint("[InitClient]: Finished initializing");
}
void cGameApp::ClientFrame( float timeDelta )
{
/**
* Any messages from the server? if so process them.
*/
char data[ MAX_UDPBUFFERSIZE ];
HOSTHANDLE srcHostID;
cDataExtract extract;
unsigned short amnt;
/**
* Reliable messages new include logins, new disconnects,
* votes, chat messages, name/model changes,
* Chat messages, votes, name changes, spawns, deaths...
* We're not supporting all those options, but feel free to add them.
*/
while( ( amnt = m_comm.GetReliableData( data, MAX_UDPBUFFERSIZE, &srcHostID ) ) != 0 )
{
extract.SetBuffer( data, amnt * 8 );
cNetMessage* pMsg = cNetMessageMaker::ConstructMessage(
(uchar*)extract.GetBuffer(),
extract.GetBufferLengthInBytes() );
pMsg->SetFrom( srcHostID );
pMsg->Exec();
delete pMsg;
}
/**
* Unreliable messages are pretty much updates and that's it.
*/
while( ( amnt = m_comm.GetUnreliableData( data, MAX_UDPBUFFERSIZE, &srcHostID ) ) != 0 )
{
extract.SetBuffer( data, amnt * 8 );
cNetMessage* pMsg = cNetMessageMaker::ConstructMessage(
(uchar*)extract.GetBuffer(),
extract.GetBufferLengthInBytes() );
pMsg->SetFrom( srcHostID );
pMsg->Exec();
delete pMsg;
}
/**
* In here is where we should get input.
*/
HandleInput();
/**
* Send our movement for this frame out on the wire.
*/
if(
m_pPlayer &&
m_pPlayer->GetStatus() == gesAlive &&
m_bInputTaken )
{
// Send the desired state to the server
cNM_MiniStateChangeRequest msg(
m_pPlayer->GetID(),
m_desiredState );
SendToServerUR( msg );
m_bInputTaken = false;
}
/**
* Run a mortis check (kill any mortisable objects)
*/
m_pWorld->EntIterStart();
while( !m_pWorld->EntIterDone() )
{
MortisCheck( m_pWorld->EntIterCurr() );
m_pWorld->EntIterNext();
}
Sleep( 10 );
}
void cGameApp::DrawConsole()
{
int nLines = m_console.size();
for( int i=0; i<nLines; i++ )
{
Graphics()->DrawTextString(
1, 1+16 * i, D3DCOLOR_XRGB( 255, 0, 0),
m_console[i].c_str() );
}
for( i=0; i<nLines; i++ )
{
Graphics()->DrawTextString(
0, 16 * i, D3DCOLOR_XRGB( 255, 255, 255),
m_console[i].c_str() );
}
}
void cGameApp::RenderFrame( float timeDelta )
{
// Keep this static to try to keep memory problems at bay.
static vector< cGameCell* > cellList;
cellList.reserve( m_pWorld->m_nCells );
cellList.clear();
Graphics()->BeginScene();
if( !m_bConnected )
{
Graphics()->Clear( true, true, 0, 1.f );
DrawConsole();
Graphics()->DrawTextString( 0, 160, D3DCOLOR_XRGB( 255, 0, 0), "Connecting to server..." );
Graphics()->Flip();
Sleep(100);
}
else
{
if( m_pPlayer->GetStatus() != gesUnSpawned )
{
// We can just use the yaw and pitch values.
m_pPlayer->SetYaw( m_desiredState.m_yaw );
m_pPlayer->SetPitch( m_desiredState.m_pitch );
m_pPlayer->RebuildMatrix();
matrix4 playerMat = m_pPlayer->GetMatrix();
matrix4 viewMat;
viewMat.ToInverse( playerMat );
Graphics()->SetViewMatrix( viewMat );
Graphics()->Clear( true, true, D3DCOLOR_XRGB( 255, 0, 0 ), 1.0f );
// Generate a frustum for the camera, and use it to do a portal walk.
// Some info about our rendering...
char renderInfo[256];
/**
* See if we can find the parent cell of the player
*/
sMsg msg( msgFindContainingCell, g_gameWorldID, 0 );
msg.m_pt = m_pPlayer->GetLoc();
int parentCell = MsgDaemon()->DeliverMessage( msg );
if( -1 != parentCell )
{
// We found a valid cell. Use it to do a portal walk.
matrix4 viewMat = matrix4::Inverse( m_pPlayer->GetMatrix() );
cViewCone cone(
PI/3,
Graphics()->Width(),
Graphics()->Height(),
viewMat );
cGameCell* pCameraCell = (cGameCell*)MsgDaemon()->Get(
parentCell
);
pCameraCell->PortalWalk( &cellList, cone );
sprintf( renderInfo, "%d cells traversed", cellList.size() );
}
else
{
// We aren't in the bounds of a cell. Draw
// everything.
sprintf( renderInfo, "Portal walk not performed" );
m_pWorld->TraverseAll( &cellList );
}
// Draw all cells in the list
for_each(
cellList.begin(),
cellList.end(),
ptr_fun(DrawCell) );
cellList.clear();
Graphics()->GetDevice()->SetRenderState( D3DRS_LIGHTING, TRUE );
InitLights();
// Draw all of the objects
m_pWorld->EntIterStart();
while( !m_pWorld->EntIterDone() )
{
DrawEnt( m_pWorld->EntIterCurr() );
m_pWorld->EntIterNext();
}
Graphics()->GetDevice()->SetRenderState( D3DRS_LIGHTING, FALSE );
if( m_bDrawScoreboard )
{
DrawScoreBoard();
}
else
{
DrawConsole();
}
Graphics()->DrawTextString( 0, 180, D3DCOLOR_XRGB( 0, 0, 255), renderInfo );
}
else if( m_pPlayer->GetStatus() == gesUnSpawned )
{
Graphics()->Clear( true, true, 0, 1.f );
DrawConsole();
Graphics()->DrawTextString( 0, 160, D3DCOLOR_XRGB( 0, 0, 255), "Press Fire key to spawn" );
}
else
{
Graphics()->Clear( true, true, 0, 1.f );
DrawConsole();
Graphics()->DrawTextString( 0, 160, D3DCOLOR_XRGB( 0, 0, 255), "Connected to server..." );
}
}
Graphics()->EndScene();
Graphics()->Flip();
}
void cGameApp::AddTextLine( const char* text )
{
// Take the top line off
m_console.pop_front();
// Insert the line on the bottom
m_console.push_back( string( text ) );
}
uint cGameApp::ProcMsg( const sMsg& msg )
{
cNetMessage* pMsg;
switch( msg.m_type )
{
case msgPrintString:
assert( msg.m_pData );
AddTextLine( (const char*)msg.m_pData );
return 0;
case msgPlayerCreated:
{
int pID = msg.m_i[0];
m_bConnected = true;
m_pPlayer = (cGamePlayerEnt*)MsgDaemon()->Get(pID);
// Don't forget to init the global id
g_pPlayerID = pID;
}
return 0;
case msgSendToServerR:
pMsg = (cNetMessage*)msg.m_pData;
SendToServerR( *pMsg );
return 0;
case msgSendToServerUR:
pMsg = (cNetMessage*)msg.m_pData;
SendToServerUR( *pMsg );
return 0;
case msgGetServerTime:
return m_comm.GetClock().GetTime();
default:
DP0("Bad Message got to cGame\n");
return -1;
}
}
////////////////////////////////////////////////////////////////////////////////
void cGameApp::ParseCmdLine( char *cmdLine )
{
if( cmdLine == NULL )
return;
m_localPlayerName = string("Unnamed player");
// Set up some of our options
m_bInverseMouse = false;
// Now scan it for game-related options
char pLclCmdLine[ 1024 ], *pTok;
strcpy( pLclCmdLine, cmdLine );
pTok = strtok( pLclCmdLine, " " );
if( !pTok ) return;
do
{
if( strcmp( pTok, "-client" ) == 0 )
{
// Grab the sever address
pTok = strtok( NULL, " " );
m_IPAddress = string( pTok );
// Check the IP for correctness.
if( strchr( m_IPAddress.c_str(), '.' ) == 0 )
throw cGameError( "[cGameApp::ParseCmdLine]: Invalid IP address specified." );
}
else if( strcmp( pTok, "-name" ) == 0 )
{
pTok = strtok( NULL, " " );
m_localPlayerName = string( pTok );
}
else if( strcmp( pTok, "-imouse" ) == 0 )
{
m_bInverseMouse = true;
}
else if( strcmp( pTok, "-noTex" ) == 0 )
{
g_useTextures = 0;
}
} while( pTok = strtok( NULL, " " ) );
}
////////////////////////////////////////////////////////////////////////////////
// Timeout between weapon shots (in milliseconds)
const DWORD c_weapTimeout = 1500;
void cGameApp::MakeFireRequest()
{
// Don't fire if we're not alive
if( m_pPlayer->GetStatus() != gesAlive )
{
return;
}
// First attempt should succeed.
static DWORD lastFire = timeGetTime() - c_weapTimeout;
DWORD currTime = timeGetTime();
if( lastFire + c_weapTimeout > currTime )
{
// Not enough time has elapsed.
return;
}
// Reset the last fire time, since we're firing now.
lastFire = currTime;
// Play the fire sound.
cSoundWrapper *pSoundWrap = (cSoundWrapper*)Resources()->Get( 202 );
pSoundWrap->Play();
cNM_ProjFireRequest msg( m_pPlayer->GetID() );
SendToServerUR( msg );
}
////////////////////////////////////////////////////////////////////////////////
void cGameApp::SendToServerR( cNetMessage& nMsg )
{
uchar buff[MAX_UDPBUFFERSIZE];
int len = nMsg.SerializeTo( buff );
m_comm.ReliableSendTo(
(char*)buff,
len,
m_serverHost );
}
void cGameApp::SendToServerUR( cNetMessage& nMsg )
{
uchar buff[MAX_UDPBUFFERSIZE];
int len = nMsg.SerializeTo( buff );
m_comm.UnreliableSendTo(
(char*)buff,
len,
m_serverHost );
}
void cGameApp::HandleInput()
{
if( m_pPlayer )
m_desiredState = m_pPlayer->GetState();
/**
* Reset our deltas
*/
m_deltaYaw = 0;
m_deltaPitch = 0;
m_deltaLoc = point3::Zero;
m_bInputTaken = false;
/**
* Get input
*/
if( Input() )
Input()->UpdateDevices();
/**
* If we got input, activate the input flag
*/
if( m_deltaYaw != 0 ||
m_deltaPitch != 0 ||
!(m_deltaLoc == point3::Zero) )
{
m_bInputTaken = true;
Snap( m_deltaPitch, (-PI/2)+EPSILON, (PI/2)-EPSILON );
m_desiredState.m_yaw += m_deltaYaw;
m_desiredState.m_pitch += m_deltaPitch;
m_desiredState.m_vel = m_deltaLoc;
}
}
bool PlayerCmp( cGamePlayerEnt* pA, cGamePlayerEnt* pB )
{
// pA preceeds pB if the score is higher.
if( pA->GetScore() > pB->GetScore() )
return true;
return false;
}
void cGameApp::DrawScoreBoard()
{
// Get the list of players.
vector< cGamePlayerEnt* > players;
m_pWorld->ListPlayers( &players );
// Sort the list
sort( players.begin(), players.end(), PlayerCmp );
// Display the list
int nPlayers = players.size();
int i;
for( i=0; i<nPlayers; i++ )
{
Graphics()->DrawTextString(
21, 21+16 * i, D3DCOLOR_XRGB( 0, 0, 255),
players[i]->GetName().c_str() );
Graphics()->DrawTextString(
20, 20+16*i, D3DCOLOR_XRGB( 0, 0, 255),
players[i]->GetName().c_str() );
char buff[20];
sprintf( buff, "%d", players[i]->GetScore() );
Graphics()->DrawTextString(
201, 21+16 * i, D3DCOLOR_XRGB( 0, 0, 255),
buff );
Graphics()->DrawTextString(
200, 20+16 * i, D3DCOLOR_XRGB( 0, 0, 255),
buff );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -