Page 3. Microsoft XNA's Game Time and Aspect Ratios
Last updated
Last updated
Before you jump into the project, it's important to make sure you've got the general framework covered. If you're entirely new to Microsoft XNA and MonoGame, it's recommended to start with our introductory project. Please follow the walkthrough provided on.
List of Prerequisites:
A working installation of Visual Studio
MonoGame framework installed
.xnb of your desired font (Review Page 1 to make one)
Start by importing the necessary libraries. Open your Game1.cs
file and include the following namespaces at the top.
Microsoft.Xna.Framework
This is the core MonoGame library that provides the fundamental game loop, input management, and other essential game development functionalities. It gives you the foundation to build upon for your game logic.
This library specializes in rendering graphics and textures on the screen. It allows you to draw sprites, and shapes, and utilize graphical effects. This is what you'll use for any graphical elements, like animated text in this tutorial.
After importing the essential libraries, you can move on to declaring your namespace and class. Within the Game1
class, you will initialize several key variables to manage game time and aspect ratios. Here's how the class should look:
GraphicsDeviceManager graphics;
: Manages the configuration and setup of the graphics device, including the game window.
SpriteBatch spriteBatch;
: Enables drawing textures and fonts on the screen.
int frameRate, frameCounter;
: These are utilized for calculating and displaying the current frame rate.
TimeSpan elapsedTime;
: Keeps track of time elapsed, aiding in frame rate calculation.
float aspectRatio;
: Helps in maintaining consistent aspect ratios across varied screen dimensions.
frameRate
The frameRate
variable keeps track of the game's calculated frame rate, which is the frequency of screen updates, measured in frames per second (FPS). Knowing your frame rate can help you optimize your game for varying systems.
frameCounter
The frameCounter
variable counts frames as they're rendered. It works in tandem with elapsedTime
to compute the actual frame rate. Essentially, it keeps a tally of the number of frames drawn within a given time frame.
this.TargetElapsedTime = TimeSpan.FromTicks(166667);
TargetElapsedTime: This property sets the amount of time that should elapse between each call to the Update
method. It essentially sets the game's target frame rate.
TimeSpan.FromTicks: This method converts a time in ticks to a TimeSpan
object. A tick in .NET is 100 nanoseconds.
166,667 ticks: 166,667 ticks at 100 nanoseconds per tick equates to 16,666,700 nanoseconds or 16.6667 milliseconds. Since there are 1000 milliseconds in a second, dividing 1000 by 16.6667 gives us roughly 60. This is how the value of 166,667 ticks corresponds to 60 frames per second (FPS).
Formula to find ticks for other FPS:
For example, for 30 FPS, the ticks would be (1 / 30) * 10,000,000 = 333,333.33, which you can round to 333,333 ticks.
TargetElapsedTime
and elapsedTime
Purpose:
TargetElapsedTime
is what you set to control how often the game's Update
method gets called.
elapsedTime
is used for tracking how much time has actually passed since the game started or since you last checked it.
Control vs. Measure:
TargetElapsedTime
is a control variable that you set to tell the game engine your desired frame rate.
elapsedTime
is a measurement variable that tells you the actual elapsed time during game execution. This can be useful for timing animations, game events, and more.
Type:
TargetElapsedTime
is a property of the Game
class.
elapsedTime
is a variable you define and manage within your code.
aspectRatio = 4f / 3f;
Numbers 4 and 3: The aspect ratio 4:3 is a common aspect ratio used in various displays. It simply means that for every 4 units of width, there are 3 units of height. This ratio ensures that the display won't look stretched or squashed.
The 'f' after the numbers: In C#, the f
specifies that the number is a floating-point number. Floating-point numbers are used for decimal or fractional calculations. Without the 'f', C# would treat the numbers as doubles, and it would lead to a type mismatch error because aspectRatio
is declared as a float.
Division operation: The division operation 4f / 3f
calculates the aspect ratio value. In this case, it would return approximately 1.3333
.
Why use a float for aspect ratio and not an integer?
Answer: Using a float allows for more precise calculations. An aspect ratio is generally not a whole number, so using a float ensures you get the most accurate representation.
Assigning to aspectRatio
: The calculated value is then assigned to the aspectRatio
variable, which can be used throughout the program to maintain the aspect ratio across different functionalities.
By setting the aspect ratio like this, you have a default value that can be used to guide how graphics and UI elements are scaled and positioned on the screen. This is particularly useful if you don't want to calculate the aspect ratio dynamically, or if you want to support a specific set of aspect ratios.
Firstly, you might ask yourself, "Why is controlling the frame rate important?" Controlling the frame rate ensures that your game runs consistently across different machines. While a faster machine might run your game at a very high frame rate, a slower one might struggle. By setting a standard frame rate, you make the gaming experience more consistent.
Explanation of Frame Rate Control Code
frameCounter++
: Increment the frame counter by 1 for each frame rendered.
elapsedTime += gameTime.ElapsedGameTime
: Add the time elapsed during the last frame to elapsedTime
.
if (elapsedTime > TimeSpan.FromSeconds(1))
: Here's a thinking point. Why do you think we check if elapsedTime
is greater than one second?
Answer: Checking against one second allows us to update the frame rate once every second.
elapsedTime -= TimeSpan.FromSeconds(1)
: We subtract one second to reset elapsedTime
.
frameRate = frameCounter
: The frame rate is updated with the total number of frames counted in the last second.
frameCounter = 0
: Resetting the frame counter for the next second.The frame rate control logic inside the Update()
method updates the frame rate once every second. This is accomplished by counting the frames rendered using frameCounter
and updating frameRate
every second based on that count.
Understanding how to manage aspect ratios is crucial for delivering a game that looks good on multiple devices. Let's get you thinking:
Why is handling different aspect ratios important for a game?
Answer: Managing aspect ratios ensures that your game's visual elements are not distorted when displayed on screens with different dimensions.
Now let's dive into setting up aspect ratio control within the Initialize()
method. As before, you'll be adding this to your existing Game1
class.
Updated Game1 Class with Aspect Ratio Control
Explanation of Aspect Ratio Control Code
aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;
: Retrieve the aspect ratio of the screen. This line gets the aspect ratio of your game window.
How can knowing the screen's aspect ratio in real-time be beneficial?
Answer: Real-time knowledge allows you to dynamically adapt the game's layout, visuals, and other screen-dependent features.
graphics.PreferredBackBufferWidth = 800;
: Here you set a preferred width for the back buffer, which is essentially your game's rendering area.
graphics.PreferredBackBufferHeight = (int)(800 / aspectRatio);
: The height is calculated based on the aspect ratio and the preferred width. This ensures that the height will adjust according to the correct aspect ratio.
graphics.ApplyChanges();
: This applies the changes made to the GraphicsDeviceManager
.
Now you've established a method for handling different aspect ratios within your Initialize()
method. This allows for a more adaptable and visually consistent game across different screens and resolutions.
Question 1:
What is the purpose of the aspectRatio
variable in the code?
Question 2:
Briefly explain how TimeSpan elapsedTime
differs from this.TargetElapsedTime
.
Question 3: Describe in your own words why you would need to manage the frame rate in a game.
Question 4: (Multiple Choice)
Suppose you want to change the frame rate to 120 FPS. What value should TargetElapsedTime
be set to in ticks?
A) 125,000
B) 83,333
C) 100,000
D) 50,000
Challenge 1: Reduce Frame Rate to 10 FPS
Your first task is to adjust TargetElapsedTime
in your code to make the game run at 10 FPS.
Challenge 2: Automatic Frame Rate Toggle
For this second challenge, let's make the frame rate change automatically every 5 seconds between 60 FPS and 30 FPS. You can use the elapsedTime
variable to keep track of the time that has passed, and then switch the frame rate.