Pulling It All Together


Before we conclude this chapter on the user interface, we should look at how these classes tie into the GameEngine class. The game engine will include the attributes shown in Listing 2 “37.

Listing 2.37: GameEngine Attributes
start example
 public class CGameEngine  {  #region attributes     // A local reference to the DirectX device     private static Microsoft.DirectX.Direct3D.Device m_pd3dDevice;     private System.Windows.Forms.Form    m_WinForm;     public static GameInput          m_GameInput      = null;     private SplashScreen      m_SplashScreen = null;     private OptionScreen      m_OptionScreen = null;     public float               fTimeLeft      = 0.0f;     Thread                     m_threadTask   = null;  #endregion 
end example
 

Even though we will be displaying two different splash screens as the game starts, we only need one splash screen class reference. Note that we also have instances of the GameInput class and an OptionScreen . You will also see an instance of the Thread class. Remember, I mentioned that we might want to perform some resource loading while the splash screen is being displayed. When the game application requests us to display a splash screen, it may also give us a function to execute in parallel. The delegate for this background task is shown in the code line that follows . We will run the supplied function in a separate thread so that the file access associated with loading resources from disk does not impact our rendering loop. The actual mechanism for creating this thread will be discussed a little later during the discussion of the ShowSplash method.

 public delegate void BackgroundTask(); 

The option screen will be created and configured by the game application and passed down to the game engine. This will be done using the SetOptionScreen method (shown in Listing 2 “38) that simply copies the class reference into the game engine member variable.

Listing 2.38: SetOptionScreen Method
start example
 public void SetOptionScreen ( OptionScreen Screen )  {     m_OptionScreen = Screen;  } 
end example
 

The game engine is initialized by the game application as the application is starting up. The application supplies a handle to the application window as well as a Direct3D device that will be used in rendering. During initialization, at this point, we simply save the window handle and device references for future use and create a GameInput instance using the window form as shown in Listing 2 “39.

Listing 2.39: Initialize Method
start example
 public void Initialize ( System.Windows.Forms.Form form,     Microsoft.DirectX.Direct3D.Device pd3dDevice)  {     // Capture a reference to the window handle.     m_WinForm = form;     // For now just capture a reference to the DirectX device for future use.     m_pd3dDevice = pd3dDevice;     m_GameInput = new GameInput ( m_WinForm );  } 
end example
 

The ShowSplash method (shown in Listing 2 “40) manages the complete lifetime of the splash screen from creation to destruction. The arguments to the method are the name of the file with the splash screen image, the number of seconds to display the splash screen, and the function to be executed in the background while the splash screen is displayed. If the game engine splash screen member variable is null, this is the first time we are asked to display this splash screen. The splash screen is created and the background task, if one was specified, is started. The thread code creates a new thread, gives it a name so we can check on it later if we wish, and starts it running. The thread task should be written such that it terminates on its own. Although it is possible for the game developer to use this method to spawn worker threads that will continue running during the course of the game, that would be a poor programming practice. Such threads should be launched and managed from the game application itself.

Listing 2.40: ShowSplash Method
start example
 public bool ShowSplash ( string sFileName, int nSeconds, BackgroundTask task )  {     bool bDone = false;     if ( m_SplashScreen == null )     {        m_SplashScreen = new SplashScreen( sFileName, nSeconds);        if ( task != null )        {           m_threadTask = new Thread(new ThreadStart(task) );           m_threadTask.Name = "Game_backgroundTask";           m_threadTask.Start ();        }     }     bDone = m_SplashScreen.Render();     fTimeLeft = m_SplashScreen.fTimeLeft;     if ( bDone )     {        m_SplashScreen.Dispose();        m_SplashScreen = null;     }     return bDone;  } 
end example
 

Once the splash screen has been created, we have it render itself and let us know if the display time has expired. If the time has expired , we dispose of the splash screen to free up its resources and then set the reference back to null so that we are all set to display another splash screen later. The completion status is passed back to the game application. The application can use this information for transitioning game states.

The DoOptions method (shown in Listing 2 “41) controls the actual rendering of the option screen. Since the game application takes responsibility for creating and configuring the option screen, we just need to render it. Prior to calling the Render method though, we need to update the screen with the latest mouse movements and button states. We call the SetMousePosition method with the latest X and Y movements and the state of the primary mouse button. The Render method does the rest.

Listing 2.41: DoOptions Method
start example
 public void DoOptions ( )  {     if ( m_OptionScreen != null )     {        m_OptionScreen.SetMousePosition(m_GameInput.GetMousePoint().X,           m_GameInput.GetMousePoint().Y, m_GameInput.IsMouseButtonDown(0) );        m_OptionScreen.Render();     }  } 
end example
 

The GetPlayerInputs method (Listing 2 “42) is the last method that I am introducing for the game engine. It is simply a wrapper for the GameInput class Poll method. This way the game has control over when the inputs are polled without giving it access to the GameInput class.

Listing 2.42: GetPlayerInputs Method
start example
 public void GetPlayerInputs ( )  {     m_GameInput.Poll();  } 
end example
 

The changes to the game application in file App.cs to support the code presented in Chapter 2 appear in Listing 2 “43. The most significant changes are in the OneTimeSceneInit method. This method is called once before the processing loop begins and is the best place to initialize the game engine. After initializing the font and the game engine, it maps the Esc key on the keyboard to the application s Terminate method. This provides one of the several methods we will have for exiting the game. The console is created and the QUIT command is added to the console s command list. Finally, the option screen is created and initialized to have two buttons . The Play button does not do anything other than change state. The Quit button provides the third method for ending the game.

Listing 2.43: OneTimeSceneInit Method
start example
 protected override void OneTimeSceneInit()  {     // Initialize the font's internal textures.     m_pFont.InitializeDeviceObjects( device );           m_Engine.Initialize( this, device );           CGameEngine.Inputs.MapKeyboardAction(Key.Escape,              new ButtonAction(Terminate), true);           CGameEngine.Inputs.MapKeyboardAction(Key.A,              new ButtonAction(MoveCameraXM), false);           CGameEngine.Inputs.MapKeyboardAction(Key.W,              new ButtonAction(MoveCameraZP), false);           CGameEngine.Inputs.MapKeyboardAction(Key.S,              new ButtonAction(MoveCameraXP), false);           CGameEngine.Inputs.MapKeyboardAction(Key.Z,              new ButtonAction(MoveCameraZM), false);           CGameEngine.Inputs.MapKeyboardAction(Key.P,              new ButtonAction(ScreenCapture), true);           CGameEngine.Inputs.MapMouseAxisAction(0,              new AxisAction(PointCamera));           CGameEngine.Inputs.MapMouseAxisAction(1,              new AxisAction(PitchCamera));           m_Console = new GameEngine.Console( m_pFont, "console.jpg" );           GameEngine.Console.AddCommand("QUIT",              "Terminate the game", new CommandFunction(TerminateCommand));           GameEngine.Console.AddCommand("STATISTICS",              "Toggle statistics display", new CommandFunction(ToggleStatistics));           m_OptionScreen = new OptionScreen( "Options1.jpg" );           m_OptionScreen.AddButton( 328, 150, "PlayOff.jpg",              "PlayOn.jpg", "PlayHover.jpg", new ButtonFunction(Play) );           m_OptionScreen.AddButton( 328, 300, "OuitOff.jpg",              "QuitOn.jpg", "QuitHover.jpg", new ButtonFunction(Terminate) );           m_Engine.SetOptionScreen( m_OptionScreen );           music = new Jukebox();           music.AddSong("nadine.mp3");           music.AddSong("ComeOn.mp3");           music.AddSong("Rock.mp3");           music.Volume = 0.75f;           music.Play();  } 
end example
 

The last thing to examine is the changes to the OnKeyDown method of D3Dapp.cs (see Listing 2 “44) that was mention earlier in the Console description. Each time a key is pressed on the keyboard, a KeyDown message is sent to the application with focus. Letters, numbers , and spaces are sent straight to the AddCharacterToEntryLine method. A carriage return triggers the line to be processed . A Backspace key triggers the Backspace method. The period and minus keys require special handling, since they do not automatically get translated to the proper string by the ToString method. This is also where the F12 key is mapped to open and close the console. The last bit of code in the handler is used by the application base class to support toggling between windowed and full-screen mode by hitting the Alt-Enter key combination.

Listing 2.44: OnKeyDown Message Handler
start example
 protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e)  {    char tstr = (char)(e.KeyValue);    if ( GameEngine.Console.IsVisible &&        e.KeyData == System.Windows.Forms.Keys.Return )    {     GameEngine.Console.ProcessEntry();    }    if ( e.KeyData == System.Windows.Forms.Keys.F12 )    {     GameEngine.Console.ToggleState();    }    else if ( GameEngine.Console.IsVisible &&     (e.KeyData == System.Windows.Forms.Keys.Space       ( e.KeyData >= System.Windows.Forms.Keys.A &&     e.KeyData <= System.Windows.Forms.Keys.Z )       ( e.KeyData >= System.Windows.Forms.Keys.DO &&     e.KeyData <= System.Windows.Forms.Keys.D9 )     ) )    {     GameEngine.Console.AddCharacterToEntryLine( tstr );    }    else if ( GameEngine.Console.IsVisible &&        e.KeyData == System.Windows.Forms.Keys.OemPeriod )    {     GameEngine.Console.AddCharacterToEntryLine( "." );    }    else if ( GameEngine.Console.IsVisible &&        e.KeyData == System.Windows.Forms.Keys.OemMinus )    {     GameEngine.Console.AddCharacterToEntryLine( '-' );    }    else if ( GameEngine.Console.IsVisible &&        e.KeyData == System.Windows.Forms.Keys.Back )    {     GameEngine.Console.Backspace();    }    if ( (e.Alt) && (e.KeyCode == System.Windows.Forms.Keys.Return))    {     // Toggle the full-screen/window mode,     if( active && ready )     {      Pause( true );           try      {       ToggleFullscreen();       Pause( false );       return;      }      catch      {       DisplayErrorMsg(           new GraphicsException(GraphicsException.ErrorCode.ResizeFailed),           AppMsgType.ErrorAppMustExit);      }      finally      {       e.Handled = true;      }     }    }  } 
end example
 



Introduction to 3D Game Engine Design Using DirectX 9 and C#
Introduction to 3D Game Engine Design Using DirectX 9 and C#
ISBN: 1590590813
EAN: 2147483647
Year: 2005
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net