I often get hung up on explaining how I make my clown “bounce” on a trampoline in the Circus game that I use in my XNA presentations. I know I introduce some basic trigonometry that we’ve all long since forgotten. Considering my lack of engineering degree and poor grades in trig, I always assumed that everyone else in the room would just get it and I could easily move on.
I’ve not always found that to be the case, however. It turns out, what I am doing seems a little magical to some people and the whole point of my talks is to make game development easy to understand and take the mystery out of it.
So let’s look at how we make a clown a bounce on a trampoline.
Basic review of the game
The game is about a clown bouncing on a trampoline to pop hovering balloons without hitting the ground, but what my game sample really does is implement a “toy”. A clown is set hovering in the air with an assigned velocity vector of (0,0). Every frame in the Game class’s Update() method I always add 16 units to the velocity vector’s y direction.
Doing this every frame implements a very simple “gravity”. No matter what direction and speed the clown is moving, he will always get pulled back to the bottom of the screen again.
When the clown hits the trampoline, I could have simply inverted the velocity vector the way I do when you hit a balloon. This simple “turn around” trick does well enough up high in the balloon area, because it feels intuitive to the player and thanks to the simple “gravity” the clown will come back to earth anyways.
But when the did the same thing when bouncing on the trampoline, I ran into problems. One of the problems I ran into was that I had lots of trouble “aiming” the clown and I wondered why it was so difficult. I realized in early experiments that sometimes the path to the ground from the balloons is short and direct, and other trips might be longer (even bouncing off the sides). This means the length of the velocity vector can be very different when it hits the trampoline. If a very short trip happens, and I simply reflect the vector, I could run into a problem where the clown stops reaching the balloons.
That’s not fun. So I decided I would set the length of velocity to a fixed value every time the trampoline was hit. But what about the angle to reflect the clown back up toward the balloons?
Set a new velocity vector
I decided (based on my experiences with those old breakout style games) to set the clown’s bounce angle based on how far from the center of the trampoline the clown makes contact. If you hit absolutely directly on the center, I wanted the clown to bounce straight back up… 90 degrees. The farther you missed from the left and right, I wanted that angle of bounce to be more severe.
What you get from this is that a player can build a skill of “aiming” the clown.
So now I knew I wanted a dead center hit, where the center of the clown sprite lined up with the center of the trampoline, to bounce up 90 degrees. I also knew I wanted to increase that angle the farther right you hit, and decrease it the farther left you hit.
The angle I want to bounce back at is calculated on line 208 of Game1.cs.
A few lines earlier (197), you’ll see that I define two Rectangle structs that represent the size and current placement of the clown and triangle. XNA’s Rectangle struct has a built in Center property, which gives you the coordinates of the center of the rectangle. I used that to my advantage, but you could calculate the center of any arbitrary rectangle structure pretty easily (perhaps if you aren’t using XNA).
All I really care about are the x coordinates of those center points. I find the difference and add 90 degrees to get the angle I am going to bounce the clown up.
Now that I know the angle he is bouncing away at, how long should velocity be? I have to admit, at this point I knew the solution but I didn’t know the length I wanted. So I experimented. I tried different numbers until I was happy with the result. Remember, this is an arcade game, not a simulation.
Right triangles to the rescue
But what is the formula to figure out the new vector? I turned to trigonometry and two equations involving right triangles.
Why am I interested in right triangles? Imagine that the clown hit the trampoline slightly to the right of center, so I want him to bounce away upward and to the right. That would look a lot like the orange arrow below, which is the hypotenuse of the right triangle.
I already know the angle of the triangle, because I figured it out earlier. I know the value for h. It’s the length of velocity I want the clown to fly out at (no matter if he came in with more or less when he bounced). If I solve for y and then solve for x, I can create a new Vector2 with those coordinates. Then I can just set the clown’s velocity to that value and it’s done. The next time we enter Update(), the clown will be moved per the velocity vector and then “gravity” will slowly start bringing him back down to earth again.
XNA has a MathHelper that converts degrees to radians and back again. I wanted to think in degrees (like most of us do) but the Math.Sin() and Math.Cos() methods take angles in radians. No problem… just use the MathHelper.
At the end of this, you’ll see I multiply the Y value I just calculated by –1, which flips the sign. Why do I do this? In coordinate systems, the numbers on the y-axis go up as you move up. However, XNA puts 0,0 at the upper left corner and the numbers go up as you move down. Therefore, what I’ve calculated above is actually upside down! There is no doubt I could consolidate these lines of code but they are left separate for clarity.
You can play with the h value (which is the 800 in the above code) until you have a “bounciness” that you like. You also don’t have to use my values for gravity. Making gravity “weaker” will make the game feel more “floaty”. And let’s not forget that your game can do anything you’d like. Just remember these are very basic implementations and you may want a different feel. Don’t be afraid to experiment.