📄 game.cpp
字号:
/*******************************************************************
* Advanced 3D Game Programming using DirectX 9.0
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* copyright (c) 2003 by Peter A Walsh and Adrian Perez
* See license.txt for modification and distribution information
******************************************************************/
#include "stdafx.h"
#include "..\NetLib\cDataExtract.h"
#include "..\NetLib\cDataCompress.h"
#include "..\NetLib\cNetError.h"
#include "..\\gamecommon\\netmsgs\\LoginNM.h"
#include "..\\gamecommon\\netmsgs\\EntNM.h"
#include "..\\gamecommon\\viewcone.h"
#include <deque>
using namespace std;
void PlayGameSound( resID id )
{
cSoundWrapper* pSoundWrap = (cSoundWrapper*)Resources()->Get( id );
pSoundWrap->Play();
}
bool IsClient()
{
return true;
}
objID g_pPlayerID = -1;
objID GetClientID()
{
return g_pPlayerID;
}
int g_useTextures = 1;
////////////////////////////////////////////////////////////////////////////////
#define MAX_PLAYERS 8 // max players
#define SERVER_LISTENPORT 4000 // the port the server is listening for data on.
#define CLIENT_LISTENPORT 4001 // the port the client is listening for data on.
/**
* Drawing code is divorced from everything else so that
* the server doesn't need to include any of the DirectX
* headers (makes it smaller and faster)
*/
extern bool DrawCell( cGameCell* pCell );
extern bool DrawEnt( cGameEnt* pEnt );
extern void InitLights();
////////////////////////////////////////////////////////////////////////////////
class cGameApp
: public cApplication
, public iKeyboardReceiver
, public iMouseReceiver
, public iGameObject
{
// how long the last frame took (the next one should take about as long)
float m_timeDelta;
// the client's player
objID m_clientID;
cGamePlayerEnt* m_pPlayer;
// The world
cGameWorld* m_pWorld;
deque<string> m_console;
bool m_bConnected; // We are actually able to play.
int m_numPlayers;
string m_IPAddress, // If server, what address do we connect to?
m_localPlayerName; // The player's name, as specified on the command line.
bool m_bInverseMouse; // Invert the mouse for those player who prefer it?
MTUDP m_comm; // the network comm class
HOSTHANDLE m_serverHost; // the handle to the server host.
sEntState m_desiredState;
bool m_bInputTaken;
float m_deltaYaw, m_deltaPitch;
point3 m_deltaLoc;
bool m_bDrawScoreboard;
virtual void InitInput()
{
// We need to grab exclusive access to the input devices. This is
// for two reasons... one, when we're windowed we want to avoid
// having out-of-window clicks cause a loss of focus. Second,
// under Win2K, there is a problem with DirectInput that causes
// 'sticky' input devices if they're not grabbed exclusively.
// Two birds with one stone.
cInputLayer::Create(
AppInstance(), MainWindow()->GetHWnd(),
true, true, true );
}
public:
virtual void InitExtraSubsystems()
{
new cResourceMgr("media\\level1.res");
MsgDaemon()->RegObject( g_gameID, this );
}
void InitClient();
void ClientFrame( float timeDelta );
void RenderFrame( float timeDelta );
void DrawConsole();
void AddTextLine( const char* text );
void DrawScoreBoard();
void HandleInput();
//==========-------------------------- cApplication
virtual void Run();
virtual void DoFrame( float timeDelta );
virtual void SceneInit();
virtual void SceneEnd();
cGameApp()
: cApplication()
, m_console( 10, string("") )
{
m_pWorld = NULL;
m_title = string( "Mobots Attack!!" );
m_pPlayer = NULL;
m_numPlayers = 0;
m_bInverseMouse = false;
m_bDrawScoreboard = false;
}
~cGameApp()
{
delete m_pWorld;
delete Resources();
}
//==========-------------------------- iKeyboardReceiver
virtual void KeyUp( int key );
virtual void KeyDown( int key );
//==========-------------------------- iMouseReceiver
virtual void MouseMoved( int dx, int dy );
virtual void MouseButtonUp( int button );
virtual void MouseButtonDown( int button );
//==========-------------------------- iGameObject
virtual objID GetID(){ return g_gameID; }
virtual void SetID( objID id ){}
virtual uint ProcMsg( const sMsg& msg );
//==========--------------------------
void ParseCmdLine( char* cmdLine );
//==========-------------------------- Network message parsing
void MakeFireRequest();
void SendToServerR( cNetMessage& nMsg );
void SendToServerUR( cNetMessage& nMsg );
};
////////////////////////////////////////////////////////////////////////////////
cApplication* CreateApplication()
{
return new cGameApp();
}
void cGameApp::SceneInit()
{
LogPrint("Enter cGameApp::SceneInit()");
Graphics()->SetProjectionData( PI/3, 0.1f, 40.0f );
Graphics()->MakeProjectionMatrix();
Input()->GetKeyboard()->SetReceiver( this );
if( Input()->GetMouse() )
Input()->GetMouse()->SetReceiver( this );
// initialize our scene
LPDIRECT3DDEVICE9 pDevice = Graphics()->GetDevice();
pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
pDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
pDevice->SetRenderState( D3DRS_DITHERENABLE, FALSE );
pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
pDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
pDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR );
pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
// Load the default world.
cFile file;
file.Open( "media\\level1.world" );
m_pWorld = new cGameWorld( file );
file.Close();
Graphics()->SetWorldMatrix( matrix4::Identity );
m_timeDelta = 0.03f; // a 30th of a second is a good first value
InitClient();
AddTextLine("[SceneInit]: Finished initializing\n");
}
void cGameApp::SceneEnd()
{
/**
* Notify the server that we're outta here.
*/
if( m_pPlayer )
{
cNM_LogoutNotice msg( m_pPlayer->GetID() );
SendToServerR( msg );
}
}
void cGameApp::DoFrame( float timeDelta )
{
// update the time
m_timeDelta = timeDelta;
// Our network thread has failed, abort now.
if( m_comm.cThread::IsRunning() == false )
throw cNetError( m_comm.cThread::Error() );
ClientFrame( timeDelta );
RenderFrame( timeDelta );
m_comm.ResendPackets();
}
void cGameApp::KeyUp( int key )
{
switch( key )
{
case DIK_TAB:
m_bDrawScoreboard = false;
}
}
void cGameApp::KeyDown( int key )
{
if( !m_bConnected )
return;
m_pPlayer->RebuildMatrix();
const matrix4 mat = m_pPlayer->GetMatrix();
switch( key )
{
case DIK_GRAVE: // Clear the console
{
for( int i=0; i<10; i++ )
{
AddTextLine( "" );
}
}
break;
// fire rocket
case DIK_LCONTROL:
MakeFireRequest();
break;
// tilt up
case DIK_PRIOR:
case DIK_NUMPAD9:
{
m_deltaPitch += m_timeDelta * 1.8f;
break;
}
// tilt down
case DIK_NEXT:
case DIK_NUMPAD3:
{
m_deltaPitch -= m_timeDelta * 1.8f;
break;
}
// move forward
case DIK_UP:
case DIK_NUMPAD8:
{
point3 zAxis = mat.GetAxis(2);
m_deltaLoc += (zAxis * 10.0f);
break;
}
// move backward
case DIK_DOWN:
case DIK_NUMPAD2:
case DIK_E:
{
point3 zAxis = mat.GetAxis(2);
m_deltaLoc -= 10.0f * zAxis;
break;
}
// strafe right
case DIK_F:
{
point3 xAxis = mat.GetAxis(0);
m_deltaLoc += 10.0f * xAxis;
break;
}
// strafe left
case DIK_S:
{
point3 xAxis = mat.GetAxis(0);
m_deltaLoc -= 10.0f * xAxis;
break;
}
// move up
case DIK_SPACE:
{
point3 yAxis = mat.GetAxis(1);
m_deltaLoc += 10.0f * yAxis;
break;
}
// move down
case DIK_D:
{
point3 yAxis = mat.GetAxis(1);
m_deltaLoc -= 10.0f * yAxis;
break;
}
// turn right
case DIK_RIGHT:
case DIK_NUMPAD6:
{
m_deltaYaw += m_timeDelta * 1.8f;
break;
}
// turn left
case DIK_LEFT:
case DIK_NUMPAD4:
{
m_deltaYaw -= m_timeDelta * 1.8f;
break;
}
// turn on scoreboard
case DIK_TAB:
m_bDrawScoreboard = true;
}
}
void cGameApp::MouseMoved( int dx, int dy )
{
if( !m_bConnected )
return;
m_deltaYaw += 0.01f * (float)dx;
m_deltaPitch += 0.01f * (float)dy * ( m_bInverseMouse == true ? -1 : 1 );
}
void cGameApp::MouseButtonUp( int button )
{
if( !m_bConnected )
return;
// If we're dead, try to respawn.
if( m_pPlayer->GetStatus() == gesDead ||
m_pPlayer->GetStatus() == gesUnSpawned )
{
cNM_SpawnReq msg( m_pPlayer->GetID() );
SendToServerR( msg );
}
}
void cGameApp::MouseButtonDown( int button )
{
if( !m_bConnected )
return;
if( button == 0 )
MakeFireRequest();
if( button == 1 )
{
m_bInputTaken = true;
matrix4 mat = m_desiredState.BuildMatrix();
point3 zAxis = mat.GetAxis(2);
m_deltaLoc += 10.0f * zAxis;
}
}
void cGameApp::Run()
{
bool done = false;
static float lastTime = (float)timeGetTime();
while( !done )
{
if( Input()->GetKeyboard()->Poll( DIK_ESCAPE ) ||
Input()->GetKeyboard()->Poll( DIK_Q ) )
{
PostMessage( MainWindow()->GetHWnd(), WM_CLOSE, 0, 0 );
}
while( !done && MainWindow()->HasMessages() )
{
if( resFalse == MainWindow()->Pump() )
done = true;
}
float currTime = (float)timeGetTime();
float delta = (currTime - lastTime)/1000.f;
if( m_bActive )
{
DoFrame( delta );
}
else
{
DoIdleFrame( delta );
}
lastTime = currTime;
}
}
void cGameApp::InitClient()
{
/**
* Initially, we are not connected to the game
*/
m_bConnected = false;
/* Player name is given in the command line, or read from the init file,
* so we should have it.
* do any housekeeping, set up our sockets, and request a connection with the server.
* print some sort of ghetto "connecting" message on the screen.
*/
m_comm.Startup( CLIENT_LISTENPORT, SERVER_LISTENPORT );
m_comm.StartClient();
/**
* Client side I open a listening socket first so that I will not
* be able to send any data without being ready to read data.
* Internally to MTUDP it makes no difference.
*/
m_comm.StartListening();
m_comm.StartSending();
/**
* Open a connection to the server
*/
m_serverHost = m_comm.HostCreate( (char*)m_IPAddress.c_str(), SERVER_LISTENPORT );
/**
* Attempt to log the player in.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -