home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / Source / Chapter 12 / Game / PlayerManager.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-03-29  |  11.3 KB  |  324 lines

  1. //-----------------------------------------------------------------------------
  2. // PlayerManager.h implementation.
  3. // Refer to the PlayerManager.h interface for more details.
  4. //
  5. // Programming a Multiplayer First Person Shooter in DirectX
  6. // Copyright (c) 2004 Vaughan Young
  7. //-----------------------------------------------------------------------------
  8. #include "Main.h"
  9.  
  10. //-----------------------------------------------------------------------------
  11. // Player manager class constructor.
  12. //-----------------------------------------------------------------------------
  13. PlayerManager::PlayerManager()
  14. {
  15.     // Create the list of player objects.
  16.     m_players = new LinkedList< PlayerObject >;
  17.     m_viewingPlayer = NULL;
  18.  
  19.     // Clear all the local player's movement details.
  20.     m_localMovement = false;
  21.     m_localDrive = 0.0f;
  22.     m_localStrafe = 0.0f;
  23.     m_localFire = false;
  24.  
  25.     // Indicate that the local player needs to be spawned.
  26.     m_spawnLocalPlayer = true;
  27.     m_requestedSpawnPoint = false;
  28. }
  29.  
  30. //-----------------------------------------------------------------------------
  31. // Player manager class destructor.
  32. //-----------------------------------------------------------------------------
  33. PlayerManager::~PlayerManager()
  34. {
  35.     // Destroy the list of player objects.
  36.     m_players->ClearPointers();
  37.     SAFE_DELETE( m_players );
  38. }
  39.  
  40. //-----------------------------------------------------------------------------
  41. // Updates all of the players.
  42. //-----------------------------------------------------------------------------
  43. void PlayerManager::Update( float elapsed )
  44. {
  45.     // Ensure the scene is loaded.
  46.     if( g_engine->GetSceneManager()->IsLoaded() == false )
  47.         return;
  48.  
  49.     // Get a pointer to the local player.
  50.     PlayerObject *localPlayer = m_players->GetFirst();
  51.     if( localPlayer == NULL )
  52.         return;
  53.  
  54.     // Check if the local player is dead.
  55.     if( localPlayer->GetHealth() <= 0.0f && m_spawnLocalPlayer == false )
  56.     {
  57.         // Spawn the local player on a left mouse button press.
  58.         if( g_engine->GetInput()->GetButtonPress( 0 ) == true )
  59.             m_spawnLocalPlayer = true;
  60.  
  61.         return;
  62.     }
  63.  
  64.     // If the local player needs to be spawned and a spawn point hasn't already
  65.     // been requested, then request a spawn point from the host.
  66.     if( m_spawnLocalPlayer == true && m_requestedSpawnPoint == false )
  67.     {
  68.         // Send a request spawn point message to the host.
  69.         NetworkMessage rspm;
  70.         rspm.msgid = MSGID_SPAWN_POINT_REQUEST;
  71.         rspm.dpnid = g_engine->GetNetwork()->GetLocalID();
  72.         g_engine->GetNetwork()->Send( &rspm, sizeof( NetworkMessage ), g_engine->GetNetwork()->GetHostID() );
  73.  
  74.         // Indicate that a spawn point has been requested.
  75.         m_requestedSpawnPoint = true;
  76.  
  77.         return;
  78.     }
  79.     else if( m_spawnLocalPlayer == true )
  80.     {
  81.         // The local player needs to be spawned, but a spawn point has already
  82.         // been requested. So just return and wait for the request response.
  83.         return;
  84.     }
  85.  
  86.     // Calculate a delayed elapsed time, used for smoothing out view movement.
  87.     static float delayedElapsed = 0.0f;
  88.     delayedElapsed = delayedElapsed * 0.99f + elapsed * 0.01f;
  89.  
  90.     // Skip any further input if the local player is dying.
  91.     if( localPlayer->GetDying() == true )
  92.         return;
  93.  
  94.     // It is impossible to send network messages for every mouse movement,
  95.     // therefore the player's looking direction will be updated directly.
  96.     localPlayer->MouseLook( (float)g_engine->GetInput()->GetDeltaY() * delayedElapsed, (float)g_engine->GetInput()->GetDeltaX() * delayedElapsed );
  97.  
  98.     // Send a periodic player look update to sync the other players.
  99.     static unsigned long lookUpdate = timeGetTime();
  100.     if( lookUpdate + 100 < timeGetTime() && localPlayer->GetEnabled() == true )
  101.     {
  102.         PlayerLookUpdateMsg plum;
  103.         plum.msgid = MSGID_PLAYER_LOOK_UPDATE;
  104.         plum.dpnid = localPlayer->GetID();
  105.         plum.viewTilt = localPlayer->GetViewTilt();
  106.         plum.rotationY = localPlayer->GetRotation().y;
  107.         g_engine->GetNetwork()->Send( &plum, sizeof( PlayerLookUpdateMsg ), DPNID_ALL_PLAYERS_GROUP, DPNSEND_NOLOOPBACK );
  108.  
  109.         lookUpdate = timeGetTime();
  110.     }
  111.  
  112.     // Used for storing the local player's desired movement.
  113.     float desiredDrive = 0.0f;
  114.     float desiredStrafe = 0.0f;
  115.     bool desiredFire = false;
  116.  
  117.     // Check if the local player is trying to drive fowards or backwards.
  118.     if( g_engine->GetInput()->GetKeyPress( DIK_W, true ) )
  119.         desiredDrive = 1.0;
  120.     else if( g_engine->GetInput()->GetKeyPress( DIK_S, true ) )
  121.         desiredDrive = -1.0;
  122.  
  123.     // Check if the local player is trying to strafe left or right.
  124.     if( g_engine->GetInput()->GetKeyPress( DIK_D, true ) )
  125.         desiredStrafe = 1.0;
  126.     else if( g_engine->GetInput()->GetKeyPress( DIK_A, true ) )
  127.         desiredStrafe = -1.0;
  128.  
  129.     // Check if the local player is trying to fire their weapon.
  130.     desiredFire = g_engine->GetInput()->GetButtonPress( 0, true );
  131.  
  132.     // Check if we need to drive the local player.
  133.     if( m_localDrive != desiredDrive )
  134.     {
  135.         m_localDrive = desiredDrive;
  136.         m_localMovement = true;
  137.     }
  138.  
  139.     // Check if we need to strafe the local player.
  140.     if( m_localStrafe != desiredStrafe )
  141.     {
  142.         m_localStrafe = desiredStrafe;
  143.         m_localMovement = true;
  144.     }
  145.  
  146.     // Check if we need to fire the local player's weapon.
  147.     if( m_localFire != desiredFire )
  148.     {
  149.         m_localFire = desiredFire;
  150.         m_localMovement = true;
  151.     }
  152.  
  153.     // If the local player's movement changed or the move update timer expires,
  154.     // update the local player across the network. Since the network message is
  155.     // sent using DPNSEND_NOLOOPBACK, the local player will need to update too.
  156.     static unsigned long moveUpdate = timeGetTime();
  157.     if( ( m_localMovement == true || moveUpdate + 200 < timeGetTime() ) && localPlayer->GetEnabled() == true )
  158.     {
  159.         PlayerMoveUpdateMsg pmum;
  160.         pmum.msgid = MSGID_PLAYER_MOVE_UPDATE;
  161.         pmum.dpnid = localPlayer->GetID();
  162.         pmum.translation = localPlayer->GetTranslation();
  163.         pmum.drive = m_localDrive;
  164.         pmum.strafe = m_localStrafe;
  165.         pmum.fire = m_localFire;
  166.         g_engine->GetNetwork()->Send( &pmum, sizeof( PlayerMoveUpdateMsg ), DPNID_ALL_PLAYERS_GROUP, DPNSEND_NOLOOPBACK );
  167.         m_localMovement = false;
  168.  
  169.         localPlayer->SetDrive( m_localDrive );
  170.         localPlayer->SetStrafe( m_localStrafe );
  171.         localPlayer->SetFire( m_localFire );
  172.  
  173.         moveUpdate = timeGetTime();
  174.     }
  175. }
  176.  
  177. //-----------------------------------------------------------------------------
  178. // Spawns the local player using the given spawn point.
  179. //-----------------------------------------------------------------------------
  180. void PlayerManager::SpawnLocalPlayer( long spawnPoint )
  181. {
  182.     // Ensure the spawn point request was successful.
  183.     if( spawnPoint == -1 )
  184.     {
  185.         // End the spawn point request so a new one can be attempted.
  186.         m_requestedSpawnPoint = false;
  187.  
  188.         // Indicate that the local player needs to be spawned.
  189.         m_spawnLocalPlayer = true;
  190.  
  191.         return;
  192.     }
  193.  
  194.     // Send a message to spawn the local player at the given spawn point.
  195.     SpawnPlayerMsg spm;
  196.     spm.msgid = MSGID_SPAWN_PLAYER;
  197.     spm.dpnid = g_engine->GetNetwork()->GetLocalID();
  198.     spm.translation = g_engine->GetSceneManager()->GetSpawnPointByID( spawnPoint )->GetTranslation();
  199.     g_engine->GetNetwork()->Send( &spm, sizeof( SpawnPlayerMsg ), DPNID_ALL_PLAYERS_GROUP );
  200. }
  201.  
  202. //-----------------------------------------------------------------------------
  203. // Spawns the given player at the given translation.
  204. //-----------------------------------------------------------------------------
  205. void PlayerManager::SpawnPlayer( DPNID dpnid, D3DXVECTOR3 translation )
  206. {
  207.     // Find the player to spawn.
  208.     m_players->Iterate( true );
  209.     while( m_players->Iterate() )
  210.         if( m_players->GetCurrent()->GetID() == dpnid )
  211.             break;
  212.     if( m_players->GetCurrent() == NULL )
  213.         return;
  214.  
  215.     // Enable the player object.
  216.     m_players->GetCurrent()->SetEnabled( true );
  217.     m_players->GetCurrent()->SetVisible( true );
  218.  
  219.     // Restore the player's health.
  220.     m_players->GetCurrent()->SetHealth( 100.0f );
  221.     m_players->GetCurrent()->SetDying( false );
  222.  
  223.     // Play the idle animation twice to ensure that both animation tracks 
  224.     // contain the idle animation data. This will prevent players from 
  225.     // transitioning from the death animation when respawning. 
  226.     m_players->GetCurrent()->PlayAnimation( 0, 0.0f ); 
  227.     m_players->GetCurrent()->PlayAnimation( 0, 0.0f );
  228.  
  229.     // Set the player's translation and rotation.
  230.     m_players->GetCurrent()->SetTranslation( translation );
  231.     m_players->GetCurrent()->MouseLook( 0.0f, 0.0f, true );
  232.  
  233.     // Check if the local player was spawned.
  234.     if( m_players->GetCurrent()->GetID() == g_engine->GetNetwork()->GetLocalID() )
  235.     {
  236.         // Set local player as the viewing player.
  237.         m_players->GetCurrent()->SetIsViewing( true );
  238.         m_viewingPlayer = m_players->GetCurrent();
  239.  
  240.         // The request for a local player spawn point was successful.
  241.         m_requestedSpawnPoint = false;
  242.  
  243.         // Indicate that the local player has been spawned.
  244.         m_spawnLocalPlayer = false;
  245.     }
  246.     else
  247.         m_players->GetCurrent()->SetIsViewing( false );
  248. }
  249.  
  250. //-----------------------------------------------------------------------------
  251. // Adds a new player.
  252. //-----------------------------------------------------------------------------
  253. PlayerObject *PlayerManager::AddPlayer( PlayerInfo *player )
  254. {
  255.     // Create the script for the player's character.
  256.     Script *script = new Script( ( (PlayerData*)player->data )->character, "./Assets/Characters/" );
  257.  
  258.     // Create the player object.
  259.     PlayerObject *object = m_players->Add( new PlayerObject( player, script ) );
  260.  
  261.     // Destroy the character script.
  262.     SAFE_DELETE( script );
  263.  
  264.     return object;
  265. }
  266.  
  267. //-----------------------------------------------------------------------------
  268. // Removes the specified player.
  269. //-----------------------------------------------------------------------------
  270. void PlayerManager::RemovePlayer( DPNID dpnid )
  271. {
  272.     // Find the player to remove.
  273.     m_players->Iterate( true );
  274.     while( m_players->Iterate() )
  275.         if( m_players->GetCurrent()->GetID() == dpnid )
  276.             break;
  277.     if( m_players->GetCurrent() == NULL )
  278.         return;
  279.  
  280.     // Remove the player object.
  281.     PlayerObject *player = m_players->GetCurrent();
  282.     m_players->Remove( &player );
  283. }
  284.  
  285. //-----------------------------------------------------------------------------
  286. // Returns the local player.
  287. //-----------------------------------------------------------------------------
  288. PlayerObject *PlayerManager::GetLocalPlayer()
  289. {
  290.     return m_players->GetFirst();
  291. }
  292.  
  293. //-----------------------------------------------------------------------------
  294. // Returns the specified player.
  295. //-----------------------------------------------------------------------------
  296. PlayerObject *PlayerManager::GetPlayer( DPNID dpnid )
  297. {
  298.     m_players->Iterate( true );
  299.     while( m_players->Iterate() )
  300.         if( m_players->GetCurrent()->GetID() == dpnid )
  301.             return m_players->GetCurrent();
  302.  
  303.     return NULL;
  304. }
  305.  
  306. //-----------------------------------------------------------------------------
  307. // Returns the next iterated player from the player list.
  308. //-----------------------------------------------------------------------------
  309. PlayerObject *PlayerManager::GetNextPlayer( bool restart )
  310. {
  311.     m_players->Iterate( restart );
  312.     if( restart == true )
  313.         m_players->Iterate();
  314.  
  315.     return m_players->GetCurrent();
  316. }
  317.  
  318. //-----------------------------------------------------------------------------
  319. // Returns the currently viewing player.
  320. //-----------------------------------------------------------------------------
  321. PlayerObject *PlayerManager::GetViewingPlayer()
  322. {
  323.     return m_viewingPlayer;
  324. }