Skip to content
Lesson 2 of 14

Step 1 of 5 · Reading · ~4 min

Read

Math & Integration

2D Vectors

Every quantity in the engine you are building is a pair of numbers: a position, a velocity, a force, a direction. After this lesson your program will answer vector questions from a script: how far apart are these two points, what is the part of this motion that points along a wall, and where does a ball leave after hitting a surface?

A vector is an arrow

A 2D vector (x, y) is an arrow with a length and a direction. The same pair can mean a place ("the ball is at (3, 4)") or a displacement ("it moved by (1, -2)"). The engine mixes them constantly, so keep the arithmetic in one place.

  • Add a + b = (ax + bx, ay + by): walk along a, then along b.
  • Subtract a - b = (ax - bx, ay - by): the arrow that points from b to a. This is how you get "from body A to body B".
  • Scale s * a = (s*ax, s*ay): same direction, s times as long. A negative s flips it.

Length and direction

The length follows from Pythagoras: |a| = sqrt(ax^2 + ay^2). Many tests only need to compare distances, and for those the squared length ax^2 + ay^2 is enough: |d| < r and |d|^2 < r^2 agree when r >= 0, and the second form needs no square root.

A unit vector has length 1 and carries only direction. To normalize, divide both components by the length. The zero vector has no direction, and dividing by its length is 0 / 0. Decide what to return for it (this course returns the zero vector) and do it before dividing. Do not use a "small enough" cutoff: a legitimate vector such as (0.0003, 0.0004) is tiny but still has a direction, and it must normalize to (0.6, 0.8).

Dot product: how much do they agree?

a . b = ax*bx + ay*by, and geometrically a . b = |a| |b| cos(angle).

  • Positive: the arrows point broadly the same way. Zero: perpendicular. Negative: broadly opposite.
  • If n is a unit vector, a . n is the signed length of a's shadow on the line through n. Collision code uses this constantly: "how fast is B approaching along the contact normal" is a dot product.

Projection. The part of a that lies along b is the shadow length times the direction of b:

proj_b(a) = ( (a . b) / (b . b) ) * b

Dividing by b . b instead of assuming b is a unit vector makes it work for any non-zero b. If b is zero there is no line to project onto, so return the zero vector.

Worked trace with a = (2, 5), b = (0, 2): a . b = 10, b . b = 4, so the factor is 2.5 and the projection is (0, 5). The leftover a - proj = (2, 0) is perpendicular to b. Together they rebuild a.

2D cross product: which side?

In 2D the cross product is a single signed number: a x b = ax*by - ay*bx. Its size is the area of the parallelogram the two arrows span, and its sign says which way you turn from a to b: positive is counter-clockwise, negative is clockwise, zero means parallel. Swapping the operands flips the sign. Rotating a vector 90 degrees counter-clockwise gives the perpendicular perp(x, y) = (-y, x); edge normals of polygons come from it.

Reflection

A ball with velocity v hits a surface whose normal is the unit vector n. Split v into the part along n (the part that hits the wall) and the rest (the part sliding along it). Bouncing reverses only the first part:

v' = v - 2 (v . n) n

Only a unit n makes the factor 2 correct. If the caller hands you (0, 2) as a normal you must normalize it first. Sanity check: v = (4, -3) bouncing off a floor with n = (0, 1) has v . n = -3, so v' = (4, 3).

Common mistakes

  • Dividing by the length of the zero vector and printing nan. Guard it first.
  • Treating a short vector as the zero vector. Only an exactly zero length has no direction.
  • Projecting with (a . b) * b and forgetting the division by b . b; the answer is only right when b has length 1.
  • Reflecting about a normal that is not unit length. The bounce is then scaled wrongly.
  • Mixing up the cross product's operand order. a x b and b x a differ in sign.

Your exercise

The starter reads commands and prints results; the helpers for add, subtract, scale, length and perpendicular are already written. You implement dot, cross, normalize, project and reflect. The most likely mistake is forgetting to normalize the surface normal in reflect.

Up nextNumerical IntegrationMath & Integration

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…