Skip to content

Commit fa7885f

Browse files
committed
Update chapter 17 for new atlas
1 parent f94927a commit fa7885f

File tree

3 files changed

+43
-74
lines changed

3 files changed

+43
-74
lines changed

articles/tutorials/building_2d_games/17_scenes/index.md

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -109,28 +109,23 @@ The key changes here are:
109109
> [!TIP]
110110
> Notice that we use a two-step process for scene transitions with separate `_activeScene` and `_nextScene` fields. This design allows the current scene to complete its update/draw cycle before the transition occurs, preventing potential issues that could arise from changing scenes in the middle of processing. The actual transition happens at a controlled point in the game loop, ensuring clean disposal of the old scene before initializing the new one.
111111
112-
## Adding Scenes To Our Game
112+
## Updating the Game
113113

114-
With the scene architecture in place, the game can be broken down into scenes. We will create two scenes; a title scene and a gameplay scene.
114+
With the scene architecture in place, the game can now be updated so that it is broken down into scenes. We'll create two scenes; a title scene and a gameplay scene.
115115

116116
### The Title Scene
117117

118-
The title scene that will serve as our game's main menu. This scene will display the game title, a prompt to start the game, and an animated slime to give the scene some life.
118+
The title scene serves as the game's initial starting point, making the first impression on the player when they first launch the game. For our game, this scene will display stylized text for the title of the game and a prompt for an action for the user to perform to start the game. The stylized text is a graphic that was created and added to the texture atlas which features the title of the game with a drop shadow effect on the text. So first, let's update the texture atlas to the new version with the title graphic. Download the new texture atlas below by right-clicking the following image and saving it as *atlas.png* in the *Content/images* directory of the game project, overwriting the existing one:
119119

120-
Before we implement the Title Scene, we need to create a font for the title text. Open the *Content.mgcb* content project in the MGCB Editor and:
120+
| ![Figure 17-1: The texture atlas for our game updated to include the title sprite](./images/atlas.png) |
121+
|:------------------------------------------------------------------------------------------------------:|
122+
| **Figure 17-1: The texture atlas for our game updated to include the title sprite** |
121123

122-
1. Right-click the *fonts* directory and choose *Add > New Item...*.
123-
2. Select *SpriteFont Description (.spritefont)* from the options.
124-
3. Name the file *titleFont.spritefont* and click *Create*.
125-
4. Open the *titleFont.spritefont* file and change it to the following:
124+
Next, open the *atlas-definition.xml* file and add the region for the title sprite:
126125

127-
[!code-xml[](./snippets/titleFont.spritefont)]
126+
[!code-xml[](./snippets/atlas-definition.xml?highlight=10)]
128127

129-
Next, download the *04B_30.ttf* font below by right-clicking it, choosing "Save Link as...", and saving it in the same directory that you just created the *titleFont.spritefont* file.
130-
131-
- [04B_30.ttf](./files/04B_30.TTF)
132-
133-
Next, create the `TitleScene` class file. In the main game project:
128+
With the atlas now updated, create the `TitleScene` class file. In the main game project:
134129

135130
1. Create a new directory named *Scenes*. We'll put all of our game specific scenes here.
136131
2. Add a new class file named *TitleScene.cs* to the *Scenes* directory you just created.
@@ -144,11 +139,11 @@ Add the following fields to the `TitleScene` class:
144139

145140
[!code-csharp[](./snippets/titlescene.cs#fields)]
146141

147-
- The `TITLE` and `PRESS_ENTER` constants are the text that we'll draw to display the game title and the prompt to press enter.
148-
- The `_titleFont` and `_standardFont` fields are the two fonts we'll load and use to draw the game title and the prompt with.
149-
- `_titlePos`, `_titleOrigin`, `_pressEnterPos`, and `_pressEnterOrigin` fields will contain the precalculated positions and origins to use when rendering the game title and the press enter prompt.
150-
- The `_slime` field will store the animated sprite for the slime that will be drawn.
151-
- The `_simePos` field will store the precalculated position to draw the slime at.
142+
- The `PRESS_ENTER` constant is the text we'll draw for the press enter prompt for the user.
143+
- The `_font` field stores a reference to the sprite font we'll load to render the press enter prompt with.
144+
- The `_titleSprite` field stores a reference the sprite we'll render for the stylized title from the texture atlas
145+
- The `_titlePos` and `_pressEnterPos` fields store the precalculated positions for the title sprite and the press enter prompt text when they are drawn. Since they are stationary, we can just calculate the positions once and store it instead of calculating it each frame.
146+
- The `_pressEnterOrigin` field stores the precalculated origin for hte press enter prompt text when it is drawn. Like with the position, we only need to calculate this once and store it instead of calculating it each frame.
152147

153148
#### Title Scene Methods
154149

@@ -161,20 +156,19 @@ Add the following override for the `Initialize` method to the `TitleScene` class
161156
[!code-csharp[](./snippets/titlescene.cs#initialize)]
162157

163158
- We set the `Core.ExitOnEscape` to true to allow players to exit the game when on the title screen by pressing the escape key.
164-
- A reference to the graphics device from the `Core` instance is captured so we don't have to type `Core.Instance.GraphicsDevice` each time to use it.
165-
- The position and origins of the title text and the press enter prompt are precalculated. Their positions and origins are static as they don't move around on the screen, so we can pre-calculate them here instead of doing it each cycle in the `Draw` method.
166-
- The position of the slime is also precalculated as it doesn't move.
167-
- The scale of the slime is set to `5.0f` since we're on the title screen to fill in more space.
159+
- The bounds of the screen is captures by using the `Core.GraphicsDevice.PresentationParameters.Bounds` value.
160+
- The position to draw the title sprite is precalculated so that it will be centered horizontally and 80px down from the top of the screen. The origin is set to center.
161+
- The position to draw the press enter prompt is precalculated so that it will be centered horizontally and 100 px above the bottom of the screen. The string is measured and used to center the origin for the text.
168162

169163
##### Title Scene LoadContent
170164

171165
Add the following override for the `LoadContent` method to the `TitleScene` class:
172166

173167
[!code-csharp[](./snippets/titlescene.cs#loadcontent)]
174168

175-
- We capture a reference to the content manager from the `Core` class. This content manager is used to load content that is used in multiple scenes, so it acts as a global content manager.
176-
- The fonts are loaded. The title font is only used on the title screen, so it is loaded using the scene's content manager, while the standard font is loaded using the global content manager.
177-
- The texture atlas is loaded and the slime animated sprite is created.
169+
- The font used to draw the press enter prompt is loaded.
170+
- The texture atlas is loaded using the XML configuration file.
171+
- The `_titleSprite` is generated from the `"title-card"` region in the atlas.
178172

179173
> [!TIP]
180174
> Recall from [Chapter 05](../05_content_pipeline/index.md#contentmanager-methods) that when a [**ContentManager**](xref:Microsoft.Xna.Framework.Content.ContentManager) loads an asset for the first time, it caches it internally and the subsequent calls to load that asset will return the cached one instead of performing another disk read.
@@ -187,7 +181,6 @@ Add the following override for the `Update` method to the `TitleScene` class:
187181

188182
[!code-csharp[](./snippets/titlescene.cs#update)]
189183

190-
- The animated slime is updated.
191184
- A check is made to see if the enter key is pressed, and if so, the `Core` is told to change to the game scene.
192185

193186
> [!NOTE]
@@ -199,9 +192,9 @@ Add the following override for the `Draw` method to the `TitleScene` class:
199192

200193
[!code-csharp[](./snippets/titlescene.cs#draw)]
201194

202-
- A reference to the graphics device from the `Core` instance is captured so we don't have to type `Core.Instance.GraphicsDevice` each time to use it.
203195
- The back buffer is cleared.
204-
- The title text, press enter prompt, and the animated slime are drawn using the sprite batch provided from the `Core` class.
196+
- The title sprite is drawn at its precalculated position.
197+
- The press enter prompt is drawn at its precalculated position.
205198

206199
### The Game Scene
207200

@@ -305,9 +298,9 @@ The `Game1` class is now much simpler as most of the game logic has been moved t
305298

306299
Running the game now, we can see that once the game screen comes up, the title scene is displayed with the animated slime and the press enter prompt. The background music starts playing on this scene as well. Pressing enter from here will switch to the game scene where the game starts and we can play the game implemented thus far.
307300

308-
| ![Figure 17-1: The game launching with the title screen first, then transitioning to the game play screen when enter is pressed](./videos/gameplay.webm) |
309-
|:-------------------------------------------------------------------------------------------------------------------------------------------------------:|
310-
| **Figure 17-1: The game launching with the title screen first, then transitioning to the game play screen when enter is pressed** |
301+
| ![Figure 17-2: The game launching with the title screen first, then transitioning to the game play screen when enter is pressed](./videos/gameplay.webm) |
302+
|:--------------------------------------------------------------------------------------------------------------------------------------------------------:|
303+
| **Figure 17-2: The game launching with the title screen first, then transitioning to the game play screen when enter is pressed** |
311304

312305
## Conclusion
313306

articles/tutorials/building_2d_games/17_scenes/snippets/titlescene.cs

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,22 @@ public class TitleScene : Scene
1717
#endregion
1818
{
1919
#region fields
20-
private const string TITLE = "Dungeon Slime";
2120
private const string PRESS_ENTER = "Press Enter To Start";
2221

23-
// The font to use to render the title text
24-
private SpriteFont _titleFont;
25-
2622
// The font to use to render normal text.
27-
private SpriteFont _standardFont;
23+
private SpriteFont _font;
2824

29-
// The position to draw the title text at.
30-
private Vector2 _titlePos;
25+
// The sprite to draw for the stylized title
26+
private Sprite _titleSprite;
3127

32-
// The origin to set for the title text when drawing it.
33-
private Vector2 _titleOrigin;
28+
// The position to draw the title sprite at.
29+
private Vector2 _titlePos;
3430

3531
// The position to draw the press enter text at.
3632
private Vector2 _pressEnterPos;
3733

3834
// The origin to set for the press enter text when drawing it.
3935
private Vector2 _pressEnterOrigin;
40-
41-
// The slime animation to give the title screen some life.
42-
private AnimatedSprite _slime;
43-
44-
// The position to draw the slime animation at.
45-
private Vector2 _slimePos;
4636
#endregion
4737

4838
#region initialize
@@ -62,52 +52,41 @@ public override void Initialize()
6252
// so we're not calculating it every draw frame.
6353
_titlePos = new Vector2(
6454
screenBounds.Width * 0.5f,
65-
100);
55+
80 + _titleSprite.Height * 0.5f);
6656

67-
Vector2 titleSize = _titleFont.MeasureString(TITLE);
68-
_titleOrigin = titleSize * 0.5f;
57+
// Center the origin of the title sprite.
58+
_titleSprite.CenterOrigin();
6959

60+
// Precalculate the position of for the press enter text so that it is
61+
// centered horizontally and place 100 pixels above the bottom of the
62+
// screen.
7063
_pressEnterPos = new Vector2(
7164
screenBounds.Width * 0.5f,
7265
screenBounds.Height - 100
7366
);
7467

75-
Vector2 pressEnterSize = _standardFont.MeasureString(PRESS_ENTER);
68+
// Precalculate the center origin of the press enter text.
69+
Vector2 pressEnterSize = _font.MeasureString(PRESS_ENTER);
7670
_pressEnterOrigin = pressEnterSize * 0.5f;
77-
78-
_slimePos = new Vector2(
79-
screenBounds.Width,
80-
screenBounds.Height
81-
) * 0.5f;
82-
83-
_slime.CenterOrigin();
84-
_slime.Scale = new Vector2(5.0f, 5.0f);
8571
}
8672
#endregion
8773

8874
#region loadcontent
8975
public override void LoadContent()
9076
{
91-
// Load the font for the title text
92-
_titleFont = Content.Load<SpriteFont>("fonts/titleFont");
93-
9477
// Load the font for the standard txt.
95-
_standardFont = Core.Content.Load<SpriteFont>("fonts/gameFont");
78+
_font = Core.Content.Load<SpriteFont>("fonts/gameFont");
9679

9780
// Create a texture atlas from the XML configuration file.
9881
TextureAtlas atlas = TextureAtlas.FromFile(Core.Content, "images/atlas-definition.xml");
9982

100-
// Create the slime animated sprite from the atlas.
101-
_slime = atlas.CreateAnimatedSprite("slime-animation");
83+
_titleSprite = atlas.CreateSprite("title-card");
10284
}
10385
#endregion
10486

10587
#region update
10688
public override void Update(GameTime gameTime)
10789
{
108-
// Update the sprite
109-
_slime.Update(gameTime);
110-
11190
// If the user presses enter, switch to the game scene.
11291
if (Core.Input.Keyboard.WasKeyJustPressed(Keys.Enter))
11392
{
@@ -124,14 +103,11 @@ public override void Draw(GameTime gameTime)
124103
// Begin the sprite batch to prepare for rendering.
125104
Core.SpriteBatch.Begin(samplerState: SamplerState.PointClamp);
126105

127-
// Draw that title text
128-
Core.SpriteBatch.DrawString(_titleFont, TITLE, _titlePos, Color.White, 0.0f, _titleOrigin, 1.0f, SpriteEffects.None, 0.0f);
106+
// Draw that title sprite
107+
_titleSprite.Draw(Core.SpriteBatch, _titlePos);
129108

130109
// Draw the press enter text
131-
Core.SpriteBatch.DrawString(_standardFont, PRESS_ENTER, _pressEnterPos, Color.White, 0.0f, _pressEnterOrigin, 1.0f, SpriteEffects.None, 0.0f);
132-
133-
// Draw the animated slime
134-
_slime.Draw(Core.SpriteBatch, _slimePos);
110+
Core.SpriteBatch.DrawString(_font, PRESS_ENTER, _pressEnterPos, Color.White, 0.0f, _pressEnterOrigin, 1.0f, SpriteEffects.None, 0.0f);
135111

136112
// Always end the sprite batch when finished.
137113
Core.SpriteBatch.End();
Binary file not shown.

0 commit comments

Comments
 (0)