One more of the many things the sample framework does is keep track of the game's frame rate. Frame rate is something that most 3D games closely track because it deals directly with the performance of the game. It is simply the number of frames rendered in any given second, and the framework calculates it using the high-resolution timer discussed earlier in this chapter. The code included on the CD only displays the frame rate in debug mode so it doesn't clutter the screen in full-screen mode. Therefore, the code in this section assumes this behavior as well. Add the following variable to your game engine class declarations: #if (DEBUG) private Direct3D.Font debugFont = null; #endif The first thing you'll notice here is that you've declared a new type of variable, the Direct3D.Font object. This object is used to render text onscreen as part of your scene. Construction Cue
Now that the variable is declared, in your OnCreateDevice method add the following code to create a new font object: #if (DEBUG) debugFont = new Direct3D.Font(device, new System.Drawing.Font("Arial", 12)); #endif The only parameters you need for this object are the rendering device and the font you want to render with. Using a default font is adequate for this scenario. Because the font object here is also a resource, make sure that you clean up that object in your OnDestroyDevice method. Add this code to that method now: #if (DEBUG) if (debugFont != null) { // Clean up the font debugFont.Dispose(); debugFont = null; } #endif One thing you might notice on the font object is that it has two "special" methods for use when a device has just been reset or is about to be lost, OnDeviceReset and OnDeviceLost, respectively. You already have methods to handle when the device has just been reset and lost, so you want to call these font methods there. Add this section of code to the beginning of your OnResetDevice method to make sure that the font behaves correctly during a device reset: #if (DEBUG) // Make sure the debug font resets correctly debugFont.OnResetDevice(); #endif You want to handle the lost case as well, so add this section of code to the OnLostDevice method: #if (DEBUG) if (debugFont != null) { // Make sure the debug font gets rid of any resources debugFont.OnLostDevice(); } #endif Now that your font is created, you can look at the implementation of the UpdateFrameStats method from the framework, which is called every frame and calculates the current frame rate. See the code in Listing 5.5 from the framework. Listing 5.5. Calculating Frame Rateprivate void UpdateFrameStats() { // Keep track of frame count double time = FrameworkTimer.GetAbsoluteTime(); State.LastStatsUpdateFrames++; if (time - State.LastStatsUpdateTime > 1.0) { float fps = (float)(State.LastStatsUpdateFrames / (time - State.LastStatsUpdateTime)); State.CurrentFrameRate = fps; State.LastStatsUpdateFrames = 0; State.LastStatsUpdateTime = time; State.FrameStats = string.Format(State.StaticFrameStats, fps.ToString("f2", System.Globalization.CultureInfo.CurrentUICulture)); } } Now that you know how the frame rate is calculated, the last thing you need to do is actually update your scene by rendering this text. Add this code to the end of your render method, directly before your EndScene call (but not inside the finally block). #if (DEBUG) // Show debug stats (in debug mode) debugFont.DrawText(null, sampleFramework.FrameStats, new System.Drawing.Rectangle(2,0,0,0), DrawTextFormat.NoClip, unchecked((int)0xffffff00)); debugFont.DrawText(null, sampleFramework.DeviceStats, new System.Drawing.Rectangle(2,15,0,0), DrawTextFormat.NoClip, unchecked((int)0xffffff00)); #endif Look at the prototype for the DrawText call; it is more or less self-explanatory. The prototype looks like this: public System.Int32 DrawText ( Microsoft.DirectX.Direct3D.Sprite sprite , System.String text , System.Drawing.Rectangle rect , Microsoft.DirectX.Direct3D.DrawTextFormat format , System.Drawing.Color color ) Because the first parameter is null, you are specifying that you want to draw directly onscreen. Sprites are used to render 2D images onto the screen, and you use them for rendering the UI of the game later. For now, however, because you are just rendering debug information, you want it rendered directly to the screen. The second parameter is the string you will be rendering, and the third parameter is the rectangle you want to render the text into. The client rectangle is perfect here, even though you wouldn't need to use it all. The last parameter is the color you want the text to be rendered. It really is as simple as that. |