# Ball Respawn

Right now the ball respawns using fixed magic values. That’s pretty boring and bad!

When the ball is served in Pong, it fires from a random position along the center line at a random angle (with some constraints). Sound’s like we’re gonna need some vector math.

We haven’t talked about vectors much yet, but to recap, a 2D vector is simply a mathematical structure composed of an x and y component. There are various clever mathematical operations we can do on vectors that make them very useful for games. C# provides us with a useful System.Numerics library that contains vector math structures; right now we use Vector2 to represent velocity.

Let’s break down some of the math here.

We want the ball to fire in a random direction, but we don’t want its trajectory to be too vertical, or it will take forever to get to one of the paddles, and it will also be very hard to hit. We also want it to travel at the same speed regardless of its direction.

Let’s start with a vector with an x component of our desired speed and a y component of 0. You can think of this as an arrow pointing directly to the right. Now imagine that arrow as the hand of a clock. How can we describe the angle of the clock hand? As the hand rotates around it differs from its original orientation in an amount of units called radians. When that angle changes by 2 times pi, it ends up in the same position. So a rotation a quarter of the way around the clock would be pi divided by 2. You can see that if we rotate our direction vector by pi/2 radians, it will face straight down. Now, what we want is for the ball to be served at angles like this: The non-shaded area represents the angles that we want the ball to be served at. What angle is that exactly?

Well, a lot of what we do in game math is guesstimation. “Close enough” can be a powerful phrase! We can always easily tweak the exact values later if we architect our game properly. If we draw it out, we know that a quarter-circle rotation is pi/2 radians. The angle of our serve range seems to be roughly half that. So our rotation would be pi/4 radians. Sounds reasonable as a starting angle to me. How do we actually represent this range?

What if the rotation is negative? Well, our positive rotations have been going clockwise - so negative rotations go counter-clockwise! That means our possible serve angle is somewhere between -pi/4 and pi/4.

So now we need to actually pick a random rotation within this range. How should we do that? C# doesn’t have anything built-in for this so I usually write a helper, since it’s so common to want a random real number in a certain range.

Let’s create PongFE/Utility/MathHelper.cs:

``````using System;

public static class MathHelper
{
private readonly static Random s_random = new Random();

public static double RandomDouble(double min, double max)
{
return (s_random.NextDouble() * (max - min)) + min;
}
}
``````

Random.NextDouble() returns a random real number between 0 and 1. So our RandomDouble function will return a random real number between low and high.

While we’re at it, let’s add a few more math helper functions.

``````    public static int Dice(int n)
{
return (int)Math.Floor(RandomDouble(0, n));
}

public static bool CoinFlip()
{
return Dice(2) == 0;
}
``````

We need one last utility function. Bizarrely, Vector2 does not provide a built-in rotation function. Let’s fix that.

In Vector2Extensions.cs:

``````    public static Vector2 Rotate(this Vector2 vector, float radians)
{
}
``````

Now we can construct a formula for our random serve direction. First, let’s change the BallSpawner to take a speed value instead of a specific velocity.

BallSpawnMessage.cs:

``````    public float Speed { get; }

...

public BallSpawnMessage(Position2D position, float speed, int width, int height)
{
Position = position;
Speed = speed;
Width = width;
Height = height;
}
``````

Now, in BallSpawner.cs:

``````    var direction = MathHelper.RandomDouble(-System.Math.PI / 4.0, System.Math.PI / 4.0);
var velocity = new Vector2(message.Speed * (MathHelper.CoinFlip() ? -1 : 1), 0).Rotate((float)direction);