Title: Use vectors to manage bouncing balls in C#
This example is similar to the one Use sprites to animate several bouncing balls in C# except it uses vectors to store information about the balls.
A vector is a direction represented by X and Y coordinates. For example, the vector <1, 3> represents the direction 1 unit to the right and 3 units up.
Vectors and points have some useful mathematics. For example, you can subtract two points to get a vector that represents the direction between them. In Figure 1, subtracting points P1 from point P2 gives the vector pointing from P1 to P2. If the points have coordinates (p1x, p1y) and (p2x, p2y), then the vector has components <p2x  p1y, p2y  p1y>.
If you add two vectors, the result is a vector representing the other two vectors used one after another. In Figure 2, the red vector represents V1 + V2. If V1 and V2 have components <v1x, v1y> and <v2x, v2y>, then the result V1 + V2 has components <v1x + v2x, v1y + v2y>.
You can also add a vector to a point to get a new point. Figure 3 shows a vector added to point P1. If P1 has coordinates (px, py) and the vector V has components <vx, vy>, then the new point has coordinates (px + vx, py + vy).
You can calculate a vector's length by using the Pythagorean theorem. The length of vector V is written V and is Sqrt(vx^{2}, vy^{2}).
You can scale a vector by multiplying its components by a number. For example, if V has components <vx, vy>, then 3 × V = <3 × v2x, 3 × v2y> and is a vector with 3 times the length of V.
You can normalize a vector by dividing it by its length. That gives you a vector pointing in the same direction as the original but with length 1.
With that background on vectors, you can now look at the Vector2D class used by this example.
public class Vector2D
{
public float X, Y;
public Vector2D(float x, float y)
{
X = x;
Y = y;
}
public Vector2D(PointF from_point, PointF to_point)
{
X = to_point.X  from_point.X;
Y = to_point.Y  from_point.Y;
}
public static Vector2D operator +(Vector2D v1, Vector2D v2)
{
return new Vector2D(v1.X + v2.X, v1.Y + v2.Y);
}
public static Vector2D operator (Vector2D v1)
{
return new Vector2D(v1.X, v1.Y);
}
public static PointF operator *(Vector2D vector, float scale)
{
return new PointF(vector.X * scale, vector.Y * scale);
}
public static PointF operator /(Vector2D vector, float scale)
{
return new PointF(vector.X / scale, vector.Y / scale);
}
public static PointF operator +(Vector2D vector, PointF point)
{
return new PointF(point.X + vector.X, point.Y + vector.Y);
}
public static PointF operator +(PointF point, Vector2D vector)
{
return new PointF(point.X + vector.X, point.Y + vector.Y);
}
}
The class defines public fields X and y to store its components. It includes two constructors, one to initialize a vector with its components and one to initialize it with two points.
The class then defines several operators for the class. For example, it defines a + operator that adds a vector to a point to get a new point.
The BallSprite class uses the Vector2D class to represent a ball's velocity. The following code shows the new version of the Move method.
// Move the ball.
public void Move()
{
// Move the ball.
Center += Velocity;
bool bounced = false;
if ((Center.X < Radius) 
(Center.X + Radius > MaxX))
{
Velocity.X = Velocity.X;
bounced = true;
}
if ((Center.Y < Radius) 
(Center.Y + Radius > MaxY))
{
Velocity.Y = Velocity.Y;
bounced = true;
}
if (bounced) Boing();
}
The new vector class makes this code much cleaner than the previous version. The code first adds the velocity vector to the ball's center point. The result is a new point giving the ball's new position.
Next the code checks the new position to see if the ball has hit one of the form's edges. If it has, the code switches the sign of the appropriate velocity component to make the ball reverse direction.
Vectors pay a small but important role in this application. They play more important roles in other geometric and graphical applications. You could perform the same operations using X and Y coordinates, but vectors make things a bit easier.
Download the example to experiment with it and to see additional details.
