Lesson 6: Follow the Bouncing Ball
This lesson introduces conditional logic and vector math by adding code to check whether the ball hits a wall and changing its velocity based on the collision.
This lesson starts off with the code as it is at the end of lesson 5.
At the end of this lesson, your code should look something like this:
Now that the ball is moving, let's say we want to make it reverse direction when it hits the edges of the window. To do this, we will need to mimic the physics of objects bouncing off of a surface. Ignoring the energy lost as the ball bounces, a simple model for this is to keep the velocity parallel to the surface the same, and reverse the velocity perpendicular to the surface. Since our boundaries are parallel to the x and y axis, we simply need to reverse either the x velocity or the y velocity when the ball hits a wall.
So we need to add code for the following behaviors:
- Detect that a wall collision has taken place.
- Reverse the x or y velocity appropriately.
In lesson 5 the x and y velocity were constants. These need to be changed to variables, just like the x and y positions were made variables in the last lesson.
Declare and initialize a Vector2 object at the top of the class just like spriteLocation was declared previously. The new line of code will look as follows:
Vector2 spriteVelocity = new Vector2(1f, 1f);
This sets the initial values of the x and y velocity to the same values as previously, just now they are variables and can be changed while the program is running.
Now in the Game1.Update() method, change
spriteLocation.X = spriteLocation.X + 1;
spriteLocation.Y = spriteLocation.Y + 1;
spriteLocation = spriteLocation + spriteVelocity;
This may look a little strange, since we don't explicity refer to X and Y. Since spriteLocation and spriteVelocity are both of type Vector2, he can be added together and the Vector2 objects know that to add two Vector2 objects together, you need to add their X values together and their Y values together.
Now immediately after those lines of code, we need to check for a collision with the walls. In order to do this, we need to use what is called a conditional statement. A conditional statement uses boolean logic (true or false) to determine whether a block of code should be executed. In C#, conditional statements use the if keyword.
So what are the conditions we need to check for to see if we've hit a wall? Well there are 4 walls, so there are 4 conditions. For the purposes of this program, we will actually check to see if the ball has intersected with the wall, which makes the calculations a bit easier. So the conditions are as follows:
- x < 0
- y < 0
- x > width of the window - width of the ball
- y > height of the window - height of the ball
For the third and fourth conditions, we need to take into account the size of the ball since x and y actually represent the top left corner of the bounding box that contains the ball.
For each of the above conditions, we need to take the following actions respectively:
- Reverse the x velocity and add the new x velocity to the x position to get the ball out from inside the wall
- Reverse the y velocity and add the new y velocity to the y position to get the ball out from inside the wall
- Same as 1
- Same as 2
Since 1 and 3 require the same action, and 2 and 4 require the same action, we can group the 4 conditions into 2 conditional statements. Writing these as code looks as follows:
if (spriteLocation.X < 0 || spriteLocation.X > graphics.GraphicsDevice.Viewport.Width - spriteTexture.Width)
// If we get in here, we've hit a vertical wall
spriteVelocity.X = -spriteVelocity.X;
spriteLocation.X = spriteLocation.X + spriteVelocity.X;
if (spriteLocation.Y < 0 || spriteLocation.Y > graphics.GraphicsDevice.Viewport.Height - spriteTexture.Height)
// If we get in here, we've hit a horizontal wall
spriteVelocity.Y = -spriteVelocity.Y;
spriteLocation.Y = spriteLocation.Y + spriteVelocity.Y;
The code in the block (between the curly braces) is only run if the conditional statement directly before it evaluates to true. the || characters mean "or" so in the case of the first "if" statement, it will be true if either spriteLocation.X is less than zero, or spriteLocation.X is greater than the width of the game surface minus the width of the ball. If the || characters were replaced with && characters, that would mean "and", and spriteLocation.X would have to be both less than zero and greater than the width of the game surface minus the width of the ball.
Run the program and you will see the ball bouncing around the screen. Change the initialization of spriteVelocity changing the X and Y values and see what happens. I would suggest different combinations of 0, 5, and 10 for the x and y velocity values.