Time for action – completing the Speller project
To complete the Speller project we need to add the CheckCollosions()
method by performing the following steps:
1. Add the
CheckCollisions()
method to theGame1
class afterCheckForNewWord()
:private void CheckCollisions() { for (int x = letters.Count - 1; x >= 0; x--) { if (new Rectangle( (int)letters[x].Position.X, (int)letters[x].Position.Y, (int)letterFont.MeasureString( letters[x].Letter).X, (int)letterFont.MeasureString( letters[x].Letter).Y).Intersects( new Rectangle( (int)playerPosition.X, (int)playerPosition.Y, playerSquare.Width, playerSquare.Height))) { if (letters[x].Letter == currentWord.Substring(currentLetterIndex, 1)) { playerScore += 1; letters.RemoveAt(x); currentLetterIndex++; } else { if (!letters[x].WasHit) { playerScore -= 1; letters[x].WasHit = true; } } } else { letters[x].WasHit = false; } } }
2. Execute the Speller project and play! The following screenshot shows how our game will look when we execute it:
What just happened?
CheckCollisions()
loops backward through the letters
list, looking for letters that the player has collided with. Going backwards is necessary because we will (potentially) be removing items from the list, which cannot be done in a foreach
loop. If we were moving forward through the list, we would disrupt our loop by deleting the current item, which would cause it to skip over the next items in the list. Moving backwards through the list allows us to remove items without adjusting our loop's logic.
In order to determine if we have collided with a letter, we build two rectangles. The first rectangle represents the position and size of the letter we are checking against, by using the letter's Position
value and the size of the letter calculated with MeasureString()
. The second rectangle represents the area occupied by the player's sprite.
The Intersects()
method of the Rectangle
class will return true if these two rectangles overlap at any point. If they do, we know we have hit a letter and need to take action.
If the letter impacted is the next letter in the word that the player is spelling, we increment the player's score and remove the letter from the list. We also advance currentLetterIndex
so that when Update()
next calls CheckForNewWord()
, we will know if this word has been completed.
If the letter is not the player's current target, we check the letter's WasHit
value. If it is false, we have not run into this letter, so we reduce the player's score and mark WasHit
to true. If WasHit
is already true, we simply do nothing so as not to deduct from the player's score multiple times while the player passes over an incorrect letter.
When the rectangles do not intersect, we know we are not currently in contact with this letter, so we set its WasHit
variable to false
. This has the effect that once we leave an incorrect letter, it becomes re-enabled for future collisions (and point deductions).
Have a go hero
Speller is a pretty simple game, but could be enhanced to make a more full-fledged game, by including the following, depending on your level of experience with 2D XNA development:
Beginner: Raise the difficulty by increasing the speed of the player's square as they complete each word.
Intermediate: Record the words with a microphone and play those recordings when a new word is generated. Instead of displaying the entire word during the
update()
method, display only the letters that have been spelled so far. This would turn the game into more of an educational kid's game with the player having to spell out the words they hear.