Provided code
This lab covers adding audio to your game, as well as text that you can
change within the code (as opposed to making an image of text, and
drawing the image). The former can add ambiance or a finishing touch
to a game, while the latter makes things like menus, scores, and exposition
much easier on both programmer and artist.
All text drawing is handled by the SpriteFont class,
in conjunction with the SpriteBatch class we've been using
frequently. There are two ways to create a SpriteFont:
SpriteFont description file for you.
Arial.spritefont file included in the provided code),
you can open it up in Visual Studio and see its contents.
You may notice that it is simply XML, with very helpful comments.
Here is the Arial.spritefont file from the provided code:
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an XML description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available
to draw with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
Redistributable sample fonts are available at
http://go.microsoft.com/fwlink/?LinkId=104778&clcid=0x409.
-->
<FontName>Arial</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>14</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true,
kerning information will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular",
"Bold", "Italic", and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing.
The default range is from 32, (ASCII space), to 126, ('~'), covering the
basic Latin character set. The characters are ordered according to
the Unicode standard. See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start> </Start>
<End>~</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>
The comments explain the use of each tag quite well.
The FontName tag must contain the name of a font installed
to the computer you compile with, but need not be installed to the
machine that plays the game.
With this XML, Visual Studio can create a *.xnb file for your
font at compile time. *.xnb is a file type used by XNA
for many things; in this case, the XNB is an image containing all of the
characters specified by the Start and End
elements in the XML, in the font specified by FontName,
at the specified size, etc. Because the font becomes an image at
compile time, a player does not need to have
your arbitrary font installed in order to play.
Sometimes, for whatever reason, this method fails to work correctly, or the license for the font you've bought may not allow you to do this. An alternative is to generate the image of the font yourself; the second method mentioned above. If you look at Lindsey.bmp, youll see what the image looks like. This is the same image format (a "bitmap") generated by the compiler when you use your XML font description. By setting the Content Processor to Sprite Font Texture, the compiler will do everything to the bitmap that it did to the XML, except for generating the bitmap (since the bitmap has already been generated).
The specification for this sprite font texture is a bit too complicated to draw one from scratch (and if you open the image in Photoshop, for example, you'll notice there is also an alpha layer that will be used by the game). Fortunately, helpful people have solved that problem, by creating the TTF to BMP Converter tool. This program will allow you to select a font from the list of fonts installed on the computer, and set all of the values you would be able to change with the XML file, and then saves the resulting bitmap for you.
Once you've got either a SpriteFont XML file or a
Sprite Font Texture loaded into your game's content pipeline,
using the font is simple. First, you'll load a SpriteFont
object in the same way we've loaded all of our Texture2Ds
so far — with the Content.Load<SpriteFont> method.
Then, rather than SpriteBatch.Draw, we'll use
SpriteBatch.DrawString. Many of the parameters for
DrawString are the same as those in Draw.
Simply remember to pass a SpriteFont instead of a
Texture2D, and a String that you want to write!
XNA has only one format that it knows how to use by default for sounds. While it is possible to create importers for other formats, the process would be complicated, and would require know the file format specifications of whatever you wished to use. However, XNA can simply and easily utilize files created with XACT (Cross-Platform Audio Creation Tool), which is what we will be using in this lab.
First, you need sound files. XACT needs files in *.wav, *.aif, or *.aiff format, but you can find tools to convert sounds files between audio formats. The two WAV files included in the provided code were originally MP3s, converted with Audacity (Audacity 1.3 is installed on the OwlNet computers).
You can find XACT in the start menu on the OwlNet machines under Programs > Microsoft Visual Express > Microsoft XNA Game Studio 4.0 > Tools > Microsoft Cross-Platform audio Creation Tool (XACT). To make sounds that you can use in your XNA game, create a new project (File > New Project), and save it in your Content directory. Create a new Wave Bank and a new Sound Bank (right click on "Wave Banks" and "Sound Banks" and select New). With your Wave Bank window selected, choose "Insert Wave Files(s)" (Ctrl+W) from the Wave Banks menu. Drag the WAV files you included to the lower half of the Sound Banks window ("Cue Names" list).
This is the extent of what is required of you in the XACT program. However, you can also use XACT to modify many attributes of your sounds — feel free to experiment. Note: If you wish to make modifications to your sounds, you must run the XACT Auditioning Utility (found in the Tools folder where you ran XACT from), and then select Audition > Connect To… in your XACT project. Select whichever item in the list is named "local". If you do not connect to an auditioning server, your sounds will fail to play inside of XACT, and if you do not have the Auditioning Tool running, you will be unable to connect to your local computer as an auditioning server.
Save your XACT project, and make sure the *.xap file and all of the audio files included in the project are in your Content directory. Add the *.xap file to your game with the Add Existing Item command. (Do not add your audio files to your Content subproject.) When you next compile your game, the compiler will generate a *.xgs, a *.xsb, and a *.xwb file for the General Settings, Sound Bank, and Wave Bank, respectively. You will need to use all three of these files to get your sounds to work.
To make use of your sounds, you will need three objects added to your game:
an AudioEngine, a SoundBank, and
a WaveBank. If you wish to change your sound volume in code
or stop multiple sounds simultaneously, you will also need at least one
AudioCategory object.
Unlike all of the other content we've loaded thus far, we cannot use
Content.Load for our audio:
engine = new AudioEngine(@"Content\Audio\SoundTextGame.xgs"); soundBank = new SoundBank(engine, @"Content\Audio\Sound Bank.xsb"); waveBank = new WaveBank(engine, @"Content\Audio\Wave Bank.xwb");You may notice that the names of the .xsb and .xwb files correspond to the names of the Sound Bank and Wave Bank in the XACT project. If you wish to use an
AudioCategory,
instantiate it with the AudioEngine.GetCatgory method.
(By default, your XACT project will have categories "Default" and "Music",
and all of your sounds will be placed in the default category.
You can create more categories and put sounds in different categories
from within XACT.)
To simply play one of your sounds until it is complete, use
SoundBank.PlayCue. If you wish to have finer control
over the sound (such as pause, resume, stop, or modifying things such as
pitch and doppler distance), create a Cue object with
SoundBank.GetCue, and then use that created Cue
object to play, stop, or alter the sound.
To modify the volume of your sound, use AudioCategory.SetVolume
— this will change the volume of all sounds in the category.
The first one is a simple one. Call AudioEngine.Update.
Your sound may work for a long time without calling it,
but eventually it will crash and burn.
Place a call to your audio engine's Update
in your game's Update method, and all should be well.
The second one is a little bit more difficult. Consider the following:
Cue laser = soundBank.GetCue("laser_fire");
laser.SetVariable("Distance", Position);
laser.Play();
What's wrong with it? Seems simple enough — we want to set the
distance of our sound based on our position, to slightly alter the sound
of the laser fire. However, this code comes with consequences,
particularly if used on a sound longer than the one second
laser_fire. Each time this code runs, a new instance of the
Cue is created, and then all references to that Cue
are lost after the method completes.
Because there are no references to the Cue, the
garbage collector knows that it's ok to remove the Cue
from memory. But if the garbage collector runs and deletes the
Cue before the Cue finishes playing,
the sound will cut off in the middle.
The solution to this second gotcha is to either use
SoundBank.PlayCue (in which case, you cannot choose to stop the
Cue prematurely, and cannot modify any variables attached to it),
or hold on to your Cue reference so that the
garbage collector does not dispose of it.
Add sound effects to the provided game code. Two sounds are provided (explosion and laser_fire), but currently not used. The code's comments indicate the logic for deciding if the player has died, if two asteroids collide with one another, when the player destroys an asteroid, and when the laser is fired. Feel free to obtain your own sounds, and to modify the existing sounds in XACT. Feel free to add sound effects to other parts of the game, such as thrusters for the ship, or some ambient music.
Add text to the corner of the screen showing the player's score, health, and/or number of lives. Feel free to use the provided Arial or Lindsey fonts, or add your own.
Bonus: When the player has run out of lives, create an "end game" or "game over" screen.
Alternatively, adding sound and text to your own arcade game by next week is also sufficient, as long as you're using the same technology.