Now it is time to turn your attention back to the development of this chapter's game project, The Story of Mighty Molly. To create this game, you follow the same five development steps that you used to create previous chapter projects.
The Story of Mighty Molly is played on a single window, although the () function and MessageBox::Show method are used to collect and display stored input and output. The game is therefore made up of one form and the 11 controls listed in Table 5.4.
Control Type | Control Name | Description |
---|---|---|
Label | lblWelcomeMsg | Displays the game's welcome message |
Label | lblCreature | Displays the creature question |
Label | lblRoom | Displays the room question |
Label | lblColor | Displays the color question |
Label | lblWeapon | Displays the weapon question |
Label | lblFood | Displays the food question |
Button | btnintroText | Shows the intro |
Button | btninstructions | Shows the instructions |
Button | btnTellStory | Tells the story |
TextBox | txbCreature | Gets the creature |
TextBox | txbRoom | Gets the room |
TextBox | txbColor | Gets the color |
TextBox | txbWeapon | Gets the weapon |
TextBox | txbFood | Gets the food |
StatusStrip | stsControl | Holds the status strip controls |
StatusLabel | tslMessage | Provides the encouragement messages |
StatusLabel | tslProgress | Displays word progress |
ProgressBar | tspProgressBar | Provides a graphical indication of the game's progress |
The first step in creating The Story of Mighty Molly is to start Visual C++ and open a new project.
If you have not already done so, start up Visual C++ 2005 Express and then click on File, New Project. The New Project dialog box appears.
Select Windows Application template.
Type The Story of Mighty Molly as the name of your new application in the Name field located at the bottom of the New Project window.
Click on OK to close the New Project dialog box.
Visual C++ creates a new project for you, including an empty form, which you'll use to create the game's user interface.
Now it's time to add the necessary controls that make up the game's user interface. The overall design of the game's interface is shown in Figure 5.8.
Start by resizing the form so that you have space to add several controls, including text boxes.
Add six Label controls to the form. By default, Visual C++ assigns the names label1 through label6 to these controls. Position the first label roughly near the top of the form, and the other five vertically on the left side.
Add five TextBox controls to the form and line them up vertically along the right side, as shown in Figure 5.8. By default, Visual C++ names these controls textBox1 through textBox5.
Add three Button controls to the form and line them as shown in Figure 5.8. By default, Visual C++ names these controls button1 through button3.
Add a StatusStrip control to the form. By default, Visual C++ assigns this control the name statusStrip1.
Add two ToolStripStatusLabel controls to the Status Strip. By default, Visual C++ assigns these controls the names of toolStripStatusLabel1 and toolStripStatusLabel2.
Add a ProgressBar control to the form.
Add a ToolTip control to the form.
Set the tab ordering so that focus starts with the first TextBox control and moves through each to the last. Doing so ensures a smoother experience when playing the game.
Figure 5.8: Completing the interface design for The Story of Mighty Molly.
The overall layout for the application's form is now complete.
It is time to customize the form and its controls. By this point in the book, you should be comfortable with the steps involved in modifying form and control properties. Instead of walking you through each step that is involved in modifying every control, I am going to provide you with tables for each control that identify the property changes that need to be made and leave it up to you to make the changes.
The property modifications that need to be made to form1 are listed in Table 5.5.
Property | Value |
---|---|
Name | frmGame |
FormBorderStyle | Fixed3D |
MaximizeBox | False |
MinimizeBox | False |
StartPosition | CenterScreen |
Text | The Story of Mighty Molly |
The property changes for each of the form's six Label controls are listed in Table 5.6.
Control | Property | Value |
---|---|---|
Label1 | Name | lblWelcomeMsg |
Font.Bold | True | |
Text | Welcome to The Story of Mighty Molly. | |
label2 | Name | lblCreature |
Text | What creature scares you the most? | |
label3 | Name | lblRoom |
Text | What's the worst room in a castle? | |
label4 | Name | lblColor |
Text | What's your favorite color? | |
label5 | Name | lblWeapon |
Text | What kind of weapon can you find lying on the ground? | |
label6 | Name | lblFood |
Text | What is your favorite food? |
The property changes for each of the three Button controls are listed in Table 5.7.
Control | Property | Value |
---|---|---|
button1 | Name | btnlntroText |
Font.Bold | True | |
Size | 90,23 | |
Text | Introduction | |
ToolTip | Click here to learn about Mighty Molly. | |
button2 | Name | btnInstructions |
Font.Bold | True | |
Size | 90,23 | |
Text | Introduction | |
ToolTip | Click here to learn how to play. | |
button3 | Name | btnTellStory |
Font.Bold | True | |
Size | 100,23 | |
Text | Tell the Story! | |
ToolTip | Click here once all the text boxes are filled to tell the story. |
The property changes for the StatusStrip control are listed in Table 5.8.
Control | Property | Value |
---|---|---|
StatusStrip1 | Name | stsControl |
Size | 452,22 |
The property changes for each of the five TextBox controls are listed in Table 5.9.
Control | Property | Value |
---|---|---|
textBox1 | Name | txbCreature |
Size | 150,20 | |
textBox2 | Name | txbRoom |
Size | 150,20 | |
textBox3 | Name | txbColor |
Size | 150,20 | |
textBox4 | Name | txbWeapon |
Size | 150,20 | |
textBox5 | Name | txbFood |
Size | 150,20 |
The property changes for the ToolStripStatusLabel control are listed in Table 5.10.
Control | Property | Value |
---|---|---|
toolStripStatusLabel1 | Name | tslMessage |
BorderSides | All | |
BorderStyle | Sunken | |
Spring | True | |
Text | Get Ready! | |
toolStripStatusLabel2 | Name | tsl Progress |
BorderSides | Left, Top,Bottom | |
BorderStyle | Sunken | |
Text | Progress: |
The property changes for the ProgressBar control are listed in Table 5.11.
Control | Property | Value |
---|---|---|
tootStripProgressBar1 | Name | tspProgressBar |
Step | 20 |
The property changes for the ToolTip control are listed in Table 5.12.
Control | Property | Value |
---|---|---|
toolTip1 | Name | tltGameTips |
Now that the game's user interface has been created and you have modified the appropriate form and control properties, it is time to begin coding. Start by clicking on the button labeled Introduction. You are taken to the btnIntroText_Click function. This function displays text in a dialog box that introduces the player to the world of Mighty Molly. The strDialogText variable is initialized with the large string that contains the introduction. Notice that the string is all one string, even though it is broken up on many lines. In Visual C++, strings that are next to each other or on a separate line without a semicolon are considered one string.
private: System::Void btnIntroText_Click(System::Object^ sender, System::EventArgs^ e) { //Store intro in dialog string String^ strDialogText = gcnew String( "Mighty Molly was the bravest of all the Mollys." "She was fearless in battle and relentless in " "everything else. No one who ever met her was " "left untouched, for the mighty one had a " "certain mystical way about her that almost " "magically seemed to rub off on those " "around her. n" "Certainly, there never was before and may " "never be again anyone as mighty as " "Mighty Molly. For those of you who " "have not heard the tales of the mighty one, " "you are in luck, because today you get the " "chance to participate in the telling of the " "mighty one's last great adventure!" ); //Show into MessageBox::Show( strDialogText, "Introduction" ); }
Click on the button that reads Instructions, which produces the btnInstructions_Click function. It performs the same steps as the Introduction button, except that the text is smaller. Again, strDialogText is being used in this function. However, because of the limits of scope, it is considered by Visual C++ to be a separate variable even though it shares the same name.
private: System::Void btnInstructions_Click(Systern: :Object^ sender, System::EventArgs^ e) { //Store intro in dialog string String^ strDialogText = gcnew String( "To play the game and participate in the " "telling of 'The Story of Mighty Molly,' " "you must enter text in the five boxes" "and then click on the 'Tell the Story!' " "button." ); //Show instructions MessageBox::Show( strDialogText, "Instructions" ); }
Click on the Tell the Story button. This generates the btnTellStory_Click function, as shown later. This function appears to be quite involved, until you realize that it only looks that way because it has so much text. The btnTellStory_Click function first tests to see if all text was entered. It does so by setting a Boolean variable, fAllTextEntered to true, optimistically assuming that all text has been entered by the time the user clicks on the button. Then the function examines the text contents of each TextBox control. The String method IsNullOrEmpty is called for each one. If the text string being examined is found to be empty, fAllTextEnterad is set to false. This then triggers an error message and the exiting of this function via the return keyword. If all text has been entered, the strDialogText String variable is used again. However, because it is in a new function, it is not the same as the other strDialogText variables used in the introduction and instruction functions.
After strDialogText has been initialized with the first part of the story, string after string is appended to it. The method that performs this is the String::Cat function, which allows several strings to be added to a string. Finally, a MessageBox::Show method displays the huge string that was assembled:
private: System::Void btnTellStory_Click(System::Object^ sender, System::EventArgs^ e) { Boolean fAllTextEntered = true; //Test to see if all text was entered //If any text string is empty, the flag // fAllTextEntered will be set to false if( String::IsNullOrEmpty( txbCreature->Text ) ) fAllTextEntered = false; if( String::IsNullOrEmpty( txbRoom->Text ) ) fAllTextEntered = false; if( String::IsNullOrEmpty( txbColor->Text ) ) fAllTextEntered = false; if( String::IsNullOrEmpty( txbWeapon->Text ) ) fAllTextEntered = false; if( String::IsNull0rEmpty( txbFood->Text ) ) fAHTextEntered = false; //If no text was entered, issue an error if( fAllTextEntered == false ) { MessageBox::Show( "You must enter all text" " to continue the game!", "Error!", MessageBoxButtons::OK, MessageBoxIcon::Stop ); return; // Exit this function } //Assemble the strings that tell the story String^ strDialogText = gcnew String( "A long time ago in a land far away, there " "was a castle where the great Prince William lived. " "Prince William was a kindly boy who cared more for " "his people than he did for himself. One day a storm " "from out of nowhere swept upon the land where " "Prince William lived. A mysterious " ); //Append the next group of text strDialogText = String::Concat( strDialogText, txbColor->Text, " mist soon followed the storm. Out of this mist " "appeared an evil ", txbCreature->Text, ".nnThe //Append the next group of text strDialogText = String::Concat( strDialogText, txbCreature->Text, "'s heart was dark and cold. The ", txbCreature->Text, " killed William's father, the " "good King Stefford. So William became the new king. " "Summoning up all his bravery, King William rode out " "ahead of his armies to do battle with the fearsome ", txbCreature->Text, ". However, King William's army was " "quickly crushed and King William was captured and " "locked away in the castle's " ); //Append the next group of text strDialogText = String::Concat( strDialogText, txbRoom->Text, ".nn" "A call went out from far and wide for a great hero " "to rescue King William. But no one dared answer " "the call except for Mighty Molly, mightiest of all " "the Mollys. Within a fortnight the mighty one " "arrived in the land where King William once ruled. " "Upon hearing of the mighty one's arrival, the", txbCreature->Text, " quickly rushed out to meet her." "nnMighty Molly and the dreaded ", txbCreature->Text ); //Append the next group of text strDialogText = String::Concat( strDialogText, " fought for 4 days and 4 nights. As they did battle " "a cloud of ", txbColor->Text, " dust gathered around " "them, making them invisible to all who tried to " "watch. Finally, at the end of the 4th day, the ", txbCreature->Text, " fell dead at the mighty one's feet." "With her strength all but gone, Mighty Molly had " "slain the " ); //Append the next group of text strDialogText = String::Concat( strDialogText, txbCreature->Text, " with her final " "blow, using a large ", txbWeapon->Text, " that she had " "fallen on during the fight.nn" "When the fight was finally over and the ", txbColor->Text, " mist finally cleared, " ); //Append the next group of text strDialogText = String::Concat( strDialogText, "a great roar arose from the people who had gathered " "around to watch. Happily, the people followed the " "mighty one to King William's castle where she " "freed him. In gratitude, good King William declared " "a holiday and ordered his cooks to prepare a great " "feast of meat, wine and ", txbFood->Text, ". At the " "feast, King William offered to give his kingdom over " "to Mighty Molly and he knelt at her knees and " "offered up his crown. But Mighty Molly turned down " "his offer, for she knew that King William was the " "true king and that as mighty as she was, she needed " "to be mightier still to rule as wisely as King " "William.nnThe End." ); MessageBox::Show( strDialogText, "The Story of Mighty Molly" ); }
The final step involves triggering the ProgressBar control's updates and seeing the unique messages that appear in the Status Strip. Click on each text box in turn and add the following code:
private: System::Void txbCreature_TextChanged(System::Object^ sender, System::EventArgs^ e) { static Boolean fProgressBarUpdated = false; //Set the progress bar message tslMessage->Text = "Be Brave!"; //Only update the progress bar once if( fProgressBarUpdated == false ) { tspProgressBar->PerformStep(); fProgressBarUpdated = true; } } private: System::Void txbRoom_TextChanged(System::Object^ sender, System::EventArgs^ e) { static Boolean fProgressBarUpdated = false; //Set the progress bar message tslMessage->Text = "Any Room Will Do!"; //Only update the progress bar once if( fProgressBarUpdated == false ) { tspProgressBar->PerformStep(); fProgressBarUpdated = true; } } private: System::Void txbColor_TextChanged(System::Object^ sender, System::EventArgs^ e) { static Boolean fProgressBarUpdated = false; //Set the progress bar message tslMessage->Text = "Any Color Will Do!"; //Only update the progress bar once if( fProgressBarUpdated == false ) { tspProgressBar->PerformStep(); fProgressBarUpdated = true; } } private: System::Void txbWeapon_TextChanged(System::Object^ sender, System::EventArgs^ e) { static Boolean fProgressBarUpdated = false; //Set the progress bar message tslMessage->Text = "Pick Something Strong!"; //Only update the progress bar once if( fProgressBarUpdated == false ) { tspProgressBar->PerformStep(); fProgressBarUpdated = true; } } private: System::Void txbFood_TextChanged(System::Object^ sender, System::EventArgs^ e) { static Boolean fProgressBarUpdated = false; //Set the progress bar message tslMessage->Text = "Pick Something Tasty!"; //Only update the progress bar once if( fProgressBarUpdated == false ) { tspProgressBar->PerformStep(); fProgressBarUpdated = true; } }
These five functions, which are nearly identical, are responsible for updating the Progress Bar and Status Strip messages. The identical fProgressBarUpdated variable in each demonstrates the concept of scope, because although these variables share the same name, they are in fact regarded by Visual C++ as entirely separate. The difference here is that each is prefaced by the static keyword. This directs Visual C++ to maintain both contents each time the function is executed. The function is, in fact, executed each keystroke as the user is typing in the TextBox control. The first time that the text box receives a keystroke, fProgressBarUpdated is defined with a value of false. After the Status Strip Label is updated with the appropriate message, fProgressBarUpdated is tested to see if it is false. The first time this happens, the code block beneath the test fProgressBarUpdated == false executes. This code block causes the Progress Bar to update itself, advancing one step. The fProgressBarUpdated variable is then set to true. Because no other logic alters it, the fProgressBarUpdated variable will forever be true. The effect of this action is that the Progress Bar is updated once and only once, when it receives its first keystroke.
Okay. That's it. The Story of Mighty Molly should be ready to run. Press F5 and put the game through its paces. If you have errors, double-check your typing. When you think you have things working the way you want, try testing the game again, this time feeding data that the game doesn't expect to receive and seeing how it handles it.