Vectors are the atoms of game math — position, velocity, direction, and force are all vectors. Learn the operations (add, scale, length, normalize) and the dot and cross products that power everything else.
A vector is a quantity with direction and magnitude, written as components — (x, y) in 2D or (x, y, z) in 3D. In games it represents a position, a velocity, a direction, or a force. Everything from moving a character to aiming a camera is vector arithmetic, so getting comfortable manipulating vectors is the foundation of all game math.
import math
# a 2D vector as a simple tuple/list (games use a Vector2/Vector3 type)
a = (3, 4)
b = (1, 2)
# addition: move by b -> combine displacements
add = (a[0] + b[0], a[1] + b[1]) # (4, 6)
# scaling: stretch/shrink by a scalar
scaled = (a[0] * 2, a[1] * 2) # (6, 8)
# subtraction: the vector FROM b TO a (direction + distance)
to_a = (a[0] - b[0], a[1] - b[1]) # (2, 2)
print(add, scaled, to_a)
# position, velocity, direction, force — all vectors. Same operations.A vector’s length (magnitude) is its size — the speed of a velocity, the distance of a displacement — found with the Pythagorean theorem. Normalizing divides a vector by its length to get a unit vector (length 1) that keeps only the direction. Unit vectors are essential: you separate "which way" from "how much" constantly, e.g. move in a direction at a set speed.
import math
def length(v):
return math.sqrt(v[0]**2 + v[1]**2)
def normalize(v):
L = length(v)
if L == 0: return (0, 0) # guard against divide-by-zero
return (v[0] / L, v[1] / L) # unit vector: same direction, length 1
v = (3, 4)
print(length(v)) # 5.0
print(normalize(v)) # (0.6, 0.8) -> length 1
# move at constant SPEED in a DIRECTION:
direction = normalize((3, 4))
speed = 10
velocity = (direction[0] * speed, direction[1] * speed) # (6, 8)The dot product multiplies two vectors into a single number that measures how aligned they are: positive when they point the same way, zero when perpendicular, negative when opposed. It is the workhorse of game math — used to find the angle between vectors, check if an enemy is in front of you, project one vector onto another, and compute lighting.
import math
def dot(a, b):
return a[0]*b[0] + a[1]*b[1]
# alignment: >0 same-ish direction, 0 perpendicular, <0 opposite
print(dot((1, 0), (1, 0))) # 1 (identical)
print(dot((1, 0), (0, 1))) # 0 (perpendicular)
print(dot((1, 0), (-1, 0))) # -1 (opposite)
# "is the enemy in FRONT of the player?" -> dot(forward, toPlayer) > 0
forward = (0, 1)
to_enemy = normalize((1, 2))
in_front = dot(forward, to_enemy) > 0 # True
# angle between two UNIT vectors: angle = acos(dot(a, b))
angle = math.degrees(math.acos(dot((1,0), normalize((1,1))))) # 45.0The cross product (in 3D) returns a vector perpendicular to two inputs — its direction gives a surface normal, and its length relates to the area they span. In 2D the "cross" is a single number whose sign tells you whether a turn is clockwise or counter-clockwise. It answers "which way does this surface face?" and "is this point left or right of that line?" — vital for normals, winding, and steering.
def cross3(a, b): # 3D cross -> a perpendicular vector
return (a[1]*b[2] - a[2]*b[1],
a[2]*b[0] - a[0]*b[2],
a[0]*b[1] - a[1]*b[0])
# a surface NORMAL from two edge vectors of a triangle:
edge1 = (1, 0, 0); edge2 = (0, 1, 0)
normal = cross3(edge1, edge2) # (0, 0, 1) -> faces +z
def cross2(a, b): # 2D "cross" -> a scalar (signed area)
return a[0]*b[1] - a[1]*b[0]
# sign tells turn direction: >0 = counter-clockwise, <0 = clockwise
print(cross2((1, 0), (0, 1))) # 1 -> left turn
# used for surface normals, polygon winding, "which side of a line" tests.