89. Slingshot refinements

To draw the target building and the flames, I went online and found images that I liked. I then added the images to the project's resources.

To add a project resource, open the Project menu and select Properties from the bottom. In the project's resources window, click the Add Resource drop-down menu and select Add Existing File. Browse to select the resource file and click Open.

I also added WAV audio files for the program to play when the user releases a shot and when a shot hits the ground. The System.Media.SoundPlayer class can play WAV files stored as project resources, so I added those files to the project as resources. Working with those files is relatively easy.

You can find lots of interesting images free at pixabay.com and commons.wikimedia.org. You can find many free audio files at freesound.org.

When a shot hits the target building, the program plays an explosion sound stored in an MP3 file. The WindowsMediaPlayer class can play that kind of file, but it requires a bit of extra effort.

First, to use the media player, you need to add a reference to its library. To do that, open the Project menu and select Add Reference. Expand the COM branch and select the Windows Media Player entry.

Next, the media player only plays files, not project resources. To allow the player to find the file, I opened the Project menu and selected Add Existing Item. In the Add Item dialog, I selected the MP3 file and clicked Add. Next, in Solution Explorer, I selected the file, set its Build Action property to Content, and set its Copy to Output Directory property to Copy if newer. Now, when Visual Studio builds the executable program, it copies the MP3 file into the executable directory so the media player can find it at runtime.

With that preparation, the program is ready to use the sound files. The following form-level declarations define sound players for the three audio files:

// Sounds.
private SoundPlayer ShotSound, SplatSound;
private WindowsMediaPlayer BoomSound;

The form's Load event handler uses the following code snippet to initialize the players:

// Load the shot and explosion sound players.
ShotSound = new SoundPlayer(Properties.Resources.boing);
SplatSound = new SoundPlayer(Properties.Resources.splat);
BoomSound = new WindowsMediaPlayer();
BoomSound.settings.autoStart = false;
BoomSound.URL = "boom.mp3";

// Play the Boom sound at zero volume to pre-load it.
BoomSound.settings.volume = 0;
BoomSound.controls.play();

This code creates SoundPlayer objects associated with the boing and splat resources.

Next, the code creates a WindowsMediaPlayer and sets its settings.autoStart property to false so the player doesn't start playing the sound as soon as it is created. The code also sets the player's URL to the name of the MP3 file.

At this point, the media player is ready to play the sound file. Unfortunately, it has a significant delay before it plays the file for the first time, presumably because it hasn't yet loaded the file. To force the player to load the file, the code sets the player's volume to zero and then calls its controls.play method to make it play the file.

Later, the program uses the audio players to play their sounds. For example, the following statement plays the shot sound:

ShotSound.Play();

The media player is a bit different. Because we earlier set the player's volume to zero, we now need to reset it to a larger value so the user can hear the sound. One place we could do that is in the MouseUp event handler. That seems like a reasonable choice because the event happens before we might need to play the sound and it doesn't happen too often (so we don't waste time increasing the volume repeatedly).

Unfortunately, a really quick user might release a shot that hits the house before the initial silent sound has finished playing. In that case, the media player seems to play the new sound before it increases its volume. Later sounds work correctly, but the first shot might not.

The program uses the following code snippet in the MouseUp event handler to deal with this problem:

BoomSound.controls.stop();
BoomSound.settings.volume = 50;

The first statement makes the media player stop playing the soundless explosion if it is still in progress. The second statement increases the player's volume to 50, which is its default value.

Playing sounds requires a few steps but, once you figure them out, they're not too hard.

The other enhancements to the program require you to draw a target building, flames, and past missed shots. The program uses the following code to declare lists to keep track of past hits and misses:

// Past hits and misses.
private List<RectangleF> Misses = new List<RectangleF>();
private List<RectangleF> Hits = new List<RectangleF>();

When a shot hits the target or the ground, the program saves the shot's location in these lists. Later, the program's Paint event handler uses the following code snippet to loop through the lists and draw the hits and misses:

// Past hits.
foreach (RectangleF hitRect in Hits)
{
e.Graphics.DrawImage(Properties.Resources.flames, hitRect);
}

// Past misses.
foreach (RectangleF missRect in Misses)
{
e.Graphics.FillEllipse(Brushes.Black, missRect);
}
...
// House.
e.Graphics.DrawImage(Properties.Resources.house, HouseRect);

The first loop draws the flames image resource at the locations of earlier hits. The second loop draws filled circles where earlier misses occurred. Later, the event handler draws the house image resource to the current target location.

The rest of the program is long but reasonably straightforward. Download the SlingshotRefinements example solution to see additional details.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset