- •Microsoft C# Programming for the Absolute Beginner
- •Table of Contents
- •Microsoft C# Programming for the Absolute Beginner
- •Introduction
- •Overview
- •Chapter 1: Basic Input and Output: A Mini Adventure
- •Project: The Mini Adventure
- •Reviewing Basic C# Concepts
- •Namespaces
- •Classes
- •Methods
- •Statements
- •The Console Object
- •.NET Documentation
- •Getting into the Visual Studio .Net Environment
- •Examining the Default Code
- •Creating a Custom Namespace
- •Adding Summary Comments
- •Creating the Class
- •Moving from Code to a Program
- •Compiling Your Program
- •Looking for Bugs
- •Getting Input from the User
- •Creating a String Variable
- •Getting a Value with the Console.ReadLine() Method
- •Incorporating a Variable in Output
- •Combining String Values
- •Combining Strings with Concatenation
- •Adding a Tab Character
- •Using the Newline Sequence
- •Displaying a Backslash
- •Displaying Quotation Marks
- •Launching the Mini Adventure
- •Planning the Story
- •Creating the Variables
- •Getting Values from the User
- •Writing the Output
- •Finishing the Program
- •Summary
- •Chapter 2: Branching and Operators: The Math Game
- •The Math Game
- •Using Numeric Variables
- •The Simple Math Game
- •Numeric Variable Types
- •Integer Variables
- •Long Integers
- •Data Type Problems
- •Math Operators
- •Converting Variables
- •Explicit Casting
- •The Convert Object
- •Creating a Branch in Program Logic
- •The Hi Bill Game
- •Condition Testing
- •The If Statement
- •The Else Clause
- •Multiple Conditions
- •Working with The Switch Statement
- •The Switch Demo Program
- •Examining How Switch Statements Work
- •Creating a Random Number
- •Introducing the Die Roller
- •Exploring the Random Object
- •Creating a Random Double with the .NextDouble() Method
- •Getting the Values of Dice
- •Creating the Math Game
- •Designing the Game
- •Creating the Variables
- •Managing Addition
- •Managing Subtraction
- •Managing Multiplication and Division
- •Checking the Answers
- •Waiting for the Carriage Return
- •Summary
- •Chapter 3: Loops and Strings: The Pig Latin Program
- •Project: The Pig Latin Program
- •Investigating The String Object
- •The String Mangler Program
- •A Closer Look at Strings
- •Using the Object Browser
- •Experimenting with String Methods
- •Performing Common String Manipulations
- •Using a For Loop
- •Examining The Bean Counter Program
- •Creating a Sentry Variable
- •Checking for an Upper Limit
- •Incrementing the Variable
- •Examining the Behavior of the For Loop
- •The Fancy Beans Program
- •Skipping Numbers
- •Counting Backwards
- •Using a Foreach Loop to Break Up a Sentence
- •Using a While Loop
- •The Magic Word Program
- •Writing an Effective While Loop
- •Planning Your Program with the STAIR Process
- •S: State the Problem
- •T: Tool Identification
- •A: Algorithm
- •I: Implementation
- •R: Refinement
- •Applying STAIR to the Pig Latin Program
- •Stating the Problem
- •Identifying the Tools
- •Creating the Algorithm
- •Implementing and Refining
- •Writing the Pig Latin Program
- •Setting Up the Variables
- •Creating the Outside Loop
- •Dividing the Phrase into Words
- •Extracting the First Character
- •Checking for a Vowel
- •Adding Debugging Code
- •Closing Up the code
- •Summary
- •Introducing the Critter Program
- •Creating Methods to Reuse Code
- •The Song Program
- •Building the Main() Method
- •Creating a Simple Method
- •Adding a Parameter
- •Returning a Value
- •Creating a Menu
- •Creating a Main Loop
- •Creating the Sentry Variable
- •Calling a Method
- •Working with the Results
- •Writing the showMenu() Method
- •Getting Input from the User
- •Handling Exceptions
- •Returning a Value
- •Creating a New Object with the CritterName Program
- •Creating the Basic Critter
- •Using Scope Modifiers
- •Using a Public Instance Variable
- •Creating an Instance of the Critter
- •Adding a Method
- •Creating the talk() Method for the CritterTalk Program
- •Changing the Menu to Use the talk() Method
- •Creating a Property in the CritterProp Program
- •Examining the Critter Prop Program
- •Creating the Critter with a Name Property
- •Using Properties as Filters
- •Making the Critter More Lifelike
- •Adding More Private Variables
- •Adding the Age() Method
- •Adding the Eat() Method
- •Adding the Play() Method
- •Modifying the Talk() Method
- •Making Changes in the Main Class
- •Summary
- •Introducing the Snowball Fight
- •Inheritance and Encapsulation
- •Creating a Constructor
- •Adding a Constructor to the Critter Class
- •Creating the CritViewer Class
- •Reviewing the Static Keyword
- •Calling a Constructor from the Main() Method
- •Working with Multiple Files
- •Overloading Constructors
- •Viewing the Improved Critter Class
- •Adding Polymorphism to Your Objects
- •Modifying the Critter Viewer in CritOver to Demonstrate Overloaded Constructors
- •Using Inheritance to Make New Classes
- •Creating a Class to View the Clone
- •Creating the Critter Class
- •Improving an Existing Class
- •Introducing the Glitter Critter
- •Adding Methods to a New Class
- •Changing the Critter Viewer Again
- •Creating the Snowball Fight
- •Building the Fighter
- •Building the Robot Fighter
- •Creating the Main Menu Class
- •Summary
- •Overview
- •Introducing the Visual Critter
- •Thinking Like a GUI Programmer
- •Creating a Graphical User Interface (GUI)
- •Examining the Code of a Windows Program
- •Adding New Namespaces
- •Creating the Form Object
- •Creating a Destructor
- •Creating the Components
- •Setting Component Properties
- •Setting Up the Form
- •Writing the Main() Method
- •Creating an Interactive Program
- •Responding to a Simple Event
- •Creating and Adding the Components
- •Adding an Event to the Program
- •Creating an Event Handler
- •Allowing for Multiple Selections
- •Choosing a Font with Selection Controls
- •Creating the User Interface
- •Examining Selection Tools
- •Creating Instance Variables in the Font Chooser
- •Writing the AssignFont() Method
- •Writing the Event Handlers
- •Working with Images and Scroll Bars
- •Setting Up the Picture Box
- •Adding a Scroll Bar
- •Revisiting the Visual Critter
- •Designing the Program
- •Determining the Necessary Tools
- •Designing the Form
- •Writing the Code
- •Summary
- •Chapter 7: Timers and Animation: The Lunar Lander
- •Introducing the Lunar Lander
- •Reading Values from the Keyboard
- •Introducing the Key Reader Program
- •Setting Up the Key Reader Program
- •Coding the KeyPress Event
- •Coding the KeyDown Event
- •Determining Which Key Was Pressed
- •Animating Images
- •Introducing the ImageList Control
- •Setting Up an Image List
- •Looking at the Image Collection
- •Displaying an Image from the Image List
- •Using a Timer to Automate Animation
- •Introducing the Timer Control
- •Configuring the Timer
- •Adding Motion
- •Checking for Keyboard Input
- •Working with the Location Property
- •Detecting Collisions between Objects
- •Coding the Crasher Program
- •Getting Values for newX and newY
- •Bouncing the Ball off the Sides
- •Checking for Collisions
- •Extracting a Rectangle from a Component
- •Getting More from the MessageBox Object
- •Introducing the MsgDemo Program
- •Retrieving Values from the MessageBox
- •Coding the Lunar Lander
- •The Visual Design
- •The Constructor
- •The timer1_Tick() Method
- •The moveShip() Method
- •The checkLanding() Method
- •The theForm_KeyDown() Method
- •The showStats() Method
- •The killShip() Method
- •The initGame() Method
- •Summary
- •Chapter 8: Arrays: The Soccer Game
- •The Soccer Game
- •Introducing Arrays
- •Exploring the Counter Program
- •Creating an Array of Strings
- •Referring to Elements in an Array
- •Working with Arrays
- •Using the Array Demo Program to Explore Arrays
- •Building the Languages Array
- •Sorting the Array
- •Designing the Soccer Game
- •Solving a Subset of the Problem
- •Adding Percentages for the Other Players
- •Setting Up the Shot Demo Program
- •Setting Up the List Boxes
- •Using a Custom Event Handler
- •Writing the changeStatus() Method
- •Kicking the Ball
- •Designing Programs by Hand
- •Examining the Form by Hand Program
- •Adding Components in the Constructor
- •Responding to the Button Event
- •Building the Soccer Program
- •Setting Up the Variables
- •Examining the Constructor
- •Setting Up the Players
- •Setting Up the Opponents
- •Setting Up the Goalies
- •Responding to Player Clicks
- •Handling Good Shots
- •Handling Bad Shots
- •Setting a New Current Player
- •Handling the Passage of Time
- •Updating the Score
- •Summary
- •Chapter 9: File Handling: The Adventure Kit
- •Introducing the Adventure Kit
- •Viewing the Main Screen
- •Loading an Adventure
- •Playing an Adventure
- •Creating an Adventure
- •Reading and Writing Text Files
- •Exploring the File IO Program
- •Importing the IO Namespace
- •Writing to a Stream
- •Reading from a Stream
- •Creating Menus
- •Exploring the Menu Demo Program
- •Adding a MainMenu Object
- •Adding a Submenu
- •Setting Up the Properties of Menu Items
- •Writing Event Code for Menus
- •Using Dialog Boxes to Enhance Your Programs
- •Exploring the Dialog Demo Program
- •Adding Standard Dialogs to Your Form
- •Using the File Dialog Controls
- •Responding to File Dialog Events
- •Using the Font Dialog Control
- •Using the Color Dialog Control
- •Storing Entire Objects with Serialization
- •Exploring the Serialization Demo Program
- •Creating the Contact Class
- •Referencing the Serializable Namespace
- •Storing a Class
- •Retrieving a Class
- •Returning to the Adventure Kit Program
- •Examining the Room Class
- •Creating the Dungeon Class
- •Writing the Game Class
- •Writing the Editor Class
- •Writing the MainForm Class
- •Summary
- •Chapter 10: Chapter Basic XML: The Quiz Maker
- •Introducing the Quiz Maker Game
- •Taking a Quiz
- •Creating and Editing Quizzes
- •Investigating XML
- •Defining XML
- •Creating an XML Document in .NET
- •Creating an XML Schema for Your Language
- •Investigating the .NET View of XML
- •Exploring the XmlNode Class
- •Exploring the XmlDocument Class
- •Reading an Existing XML Document
- •Creating the XML Viewer Program
- •Writing New Values to an XML Document
- •Building the Document Structure
- •Adding an Element to the Document
- •Displaying the XML Code
- •Examining the Quizzer Program
- •Building the Main Form
- •Writing the Quiz Form
- •Writing the Editor Form
- •Summary
- •Overview
- •Introducing the SpyMaster Program
- •Creating a Simple Database
- •Accessing the Data Server
- •Accessing the Data in a Program
- •Using Queries to Modify Data Results
- •Limiting Data with the SELECT Statement
- •Using an Existing Database
- •Adding the Capability to Display Queries
- •Creating a Visual Query Builder
- •Working with Relational Databases
- •Improving Your Data with Normalization
- •Using a Join to Connect Two Tables
- •Creating a View
- •Referring to a View in a Program
- •Incorporating the Agent Specialty Attribute
- •Working with Other Databases
- •Creating a New Connection
- •Converting a Data Set to XML
- •Reading from XML to a Data Source
- •Creating the SpyMaster Database
- •Building the Main Form
- •Editing the Assignments
- •Editing the Specialties
- •Viewing the Agents
- •Editing the Agent Data
- •Summary
- •List of Figures
- •List of Tables
- •List of Sidebars
pixels, they looked good. It’s smart to get and learn a good graphics package (such as The Gimp, included on the CD−ROM that accompanies this book) so that you can create your own images without the headache of dealing with intellectual property rights.
Getting a good starting position for the images was tricky. Although the position of the images doesn’t matter at all in terms of game play (at least, the way the game is set up right now), it is important that the players at least appear to be dispersed around the field. I decided to place all the players at the center of the field horizontally. If you subtract the player’s width from the field width and then divide by 2, you get the appropriate placement to center the player horizontally. Getting a good vertical position took more thought because the players should start out in different parts of the field. The center should be close to the opponent’s goal, and the fullback should be near the user’s goal. I found that if I divided the field height by the player number, I came up with a good vertical placement for each player except the goalie. I excluded the goalie from this calculation with an if statement because it will be placed more carefully in a later method. Also, excluding the goalie is necessary because its player number is 0 and the computer will choke if you ask it to divide by 0.
Later on, I’ll need to know which player is which, so I used a very handy property named the Tag property. The Tag is basically a free−for−all property you can use to store any kind of information you want. I’ll store the player number in the tag property for use later on in the click event.
All the picPlayer controls must respond to a click event, so I registered an event handler to a method named clickPlayer (which I’ll build shortly).
Finally, I added each picture box to the field panel.
Setting Up the Opponents
The opponents are much like the player array, but because they won’t respond to events, they are simpler to set up:
private void setupOpp(){ //set up opponents
int x; int y;
for (int i= 1; i < 5; i++){ picOpp[i] = new PictureBox(); picOpp[i].Size = new Size(25,25);
x = (int)((this.Width − picOpp[i].Width)/2); y = (int)(pnlField.Height/i − 30); picOpp[i].Location = new Point(x, y); picOpp[i].Image = myPics.Images[0]; picOpp[i].SizeMode =
PictureBoxSizeMode.StretchImage;
pnlField.Controls.Add(picOpp[i]);
} // end for loop
}// end setupOpp
The size and position of each picture box require a formula very much like the one in setupPlayer(). I set each image to the red player without a ball, which is image number 0 in the image list. I added each picture box to the controls of the panel, but adding an event listener was unnecessary.
227
Setting Up the Goalies
Both the goalies are part of the picPlayer array, and both have already been set up, for the most part. However, they deserve special treatment because they are positioned differently than the other players and have different images. Note that the user’s goalie is named GOALIE, and the opposing goalie is named SHOT.
private void setupGoalies(){ //place goalies more carefully int x;
int y;
x = (int)((pnlField.Width − picPlayer[GOALIE].Width)/2);
y = pnlField.Height − picPlayer[GOALIE].Height− 20; picPlayer[GOALIE].Location = new Point(x, y); picPlayer[SHOT].Location = new Point(x, 0); picPlayer[GOALIE].Image = myPics.Images[5]; picPlayer[SHOT].Image = myPics.Images[4];
} // end setupGoalies
I used the now familiar horizontal centering routine to get the horizontal placement of the goalies. I moved the user goalie right above the bottom of the field and placed the opposing goalie near the top of the field. I then assigned appropriate images to the goalies from the image list.
Responding to Player Clicks
The game’s action comes in two places. The passage of time will move the various player images on the field, but this has no real bearing on the game. The most important actions come when the user clicks one of the player images. Each of these images was registered with the clickPlayer() method as its event handler. This method takes action based on the algorithm described in the Shot Demo program earlier in this chapter:
private void clickPlayer(Object sender, EventArgs e){
//happens whenever you click a player Random roller = new Random();
double toSucceed; double myRoll;
//figure out which player was clicked PictureBox thePic = (PictureBox)sender;
int playerNumber = Convert.ToInt32(thePic.Tag); nextPlayer = playerNumber;
//figure out how likely success is toSucceed = shotChance[currentPlayer,
nextPlayer];
//roll a random double myRoll = roller.NextDouble();
//Announce what's going on string message = "From: " +
playerName[currentPlayer]; message += " to: " +
playerName[nextPlayer] + " "; message += toSucceed.ToString(); lblAnnounce.Text = message;
228
//look for success
if (myRoll < toSucceed){ goodShot();
}else { badShot();
}// end 'pass succceeds' if
}// end clickPlayer
This method uses a number of variables to get started. It will need to know which player currently has the ball and to which player the user intends to pass. I’ll need to do a little technical gymnastics to squeeze out this information, but it is accessible. The currentPlayer variable was declared at the class level, and its value is preset to whichever player currently has the ball. The trickier part is to determine nextPlayer, because the user doesn’t directly enter this information. Instead, he clicks a picture box. The problem is to determine which picture box the user clicked.
Fortunately, C# provides a couple good tricks for figuring out exactly this type of information. First, recall the sender object that is automatically a parameter of all event handlers. This parameter contains an object that represents whatever object triggered the event. In this case, the picture box that the user clicked will be stored in the sender variable. I cast the sender object as a picture box and stored it in the local variable thePic. Back when I created each picture box, I stored its ID in the Tag property. I can extract that property now and convert it to an integer to determine which player was clicked. That value is stored in nextPlayer.
When I know what currentPlayer and nextPlayer are, I can use them to look up the likelihood of success in the shotChance lookup table. The mechanics of this activity are the same as in the Shot Demo program. The lookup table returns a double value representing the likelihood that the given shot will succeed.
I then send a message to the announcer label of the shot being attempted and the likelihood this shot will succeed. Finally, I evaluate the shot with a random number and call a method based on the results. If the shot succeeds, control flows to the goodShot() method. If the shot fails, the badShot() method takes control.
Handling Good Shots
If the shot is successful, the next step depends on what the user was aiming at. A successful shot on the goal means that the user has scored. If the user was aiming anywhere else, the ball should be passed to that player.
public void goodShot(){ //if the shot succeeded
//check to see if it's a shot on goal if (nextPlayer == SHOT){
playerScore++;
updateScore();
MessageBox.Show("Goooooaaaaalllll!!!!");
setPlayer(HALFBACK);
}else {
lblAnnounce.Text = playerName[nextPlayer] +
"now has ball";
setPlayer(nextPlayer);
} // end 'scored a goal' if
}// end goodShot
229
The if statement checks whether the user is shooting at the goal. If so, nextPlayer is set to the same value as SHOT. The user’s score increases by 1, and the updateScore() method is employed to send a report to the scoreboard. I added a message box to enhance the mood. Finally, I gave the ball to the halfback, using the setPlayer() method.
If the user is not shooting at the goal, another player is now the current player. I copied the value of nextPlayer over to currentPlayer and set the current player visually with the setPlayer() method.
Handling Bad Shots
If the shot did not succeed, the opposing team has the ball, and I’ll give them the chance to score. This is the easiest way to control the difficulty of the game. As the code stands now, the opponent will score about 5 percent of the time the player misses a pass or shot. To make the opposing team better, change the rate to a larger number. To make the opponent weaker, use a smaller number.
public void badShot(){
Random roller = new Random(); double toSucceed;
int playerNumber;
lblAnnounce.Text = "Opponent gets ball..."; //check for opponent goal
toSucceed = roller.NextDouble(); //change the following value to alter
game difficulty
if (toSucceed < .05){ oppScore++; updateScore();
MessageBox.Show("Opponent Scores!!"); setPlayer(HALFBACK);
}else {
playerNumber = roller.Next(5); lblAnnounce.Text += "recovered by " +
playerName[playerNumber];
setPlayer(playerNumber);
} // end opponent scores if
}// end badShot
When the opponent gets the ball, I create a random double and compare it to .05. Five percent of the time, the random value will be smaller than .05, and the opponent will score. If this happens, I increase the opponent’s score, update the scoreboard, and send a message box to the user. I then give the ball to the halfback to restart play.
If the opponent’s shot did not succeed, I randomly determine which player begins with the ball and set that player as the current player.
Setting a New Current Player
Setting a player is a critical part of the game. It happens whenever the ball changes hands (okay, feet). This is a very frequent occurrence in this game. Setting a new player has two main effects. First, I change the variable currentPlayer to the new player’s number, and then I change the visual representation so that the user can see that a new player has the ball:
public void setPlayer(int playerNumber){ //given a player number, shows that player as
230