Maths for Game Development
The spatial model beneath a 2D game: coordinates, vectors, time-scaled motion, angles, transforms, and collision geometry.
A 2D game is a changing geometric model. Every visible object has a position. Every moving object has a velocity. The camera converts world positions into screen positions. Collision asks whether two regions of that model overlap. The mathematics is compact because the same operations recur in movement, aiming, animation, and physics.
Coordinates and Vectors
A position is a point in space: p = (x, y). A vector is a displacement with direction and magnitude: v = (vx, vy). In a conventional screen coordinate system, (0, 0) is the upper-left corner, x increases to the right, and y increases downward.
Vectors add component by component:
(3, 5) + (-2, 4) = (1, 9)
This is the movement operation. A player at (100, 80) with a velocity of (120, 0) is travelling right at 120 pixels per second. Position changes by velocity multiplied by elapsed time:
p_next = p + v × dt
At 60 fps, dt is about 1 / 60; the player moves about two pixels in one frame. At 30 fps, the player moves about four pixels. Both cover 120 pixels in one second. Without dt, movement speed becomes an accidental property of the display refresh rate.
Direction, Length, and Normalisation
Keyboard input produces direction vectors. Right is (1, 0), up is (0, -1), and up-right is (1, -1). The diagonal has length √2, so applying the same speed to every input makes diagonal movement about 41% faster.
The length of a vector is:
length(v) = √(vx² + vy²)
Dividing each component by that length produces a unit vector—a direction with length one:
normalise(1, -1) = (1 / √2, -1 / √2)
Multiplying that unit vector by speed gives equal movement speed in every direction. Normalisation also appears in steering, knockback, enemy pursuit, and the direction of a projectile.
Angles and Rotation
An angle converts between a direction and a rotation. Given an object at (x, y) and a target at (target_x, target_y), the vector toward the target is (dx, dy). atan2(dy, dx) converts that vector into an angle while preserving its quadrant. The inverse conversion produces a direction:
vx = cos(angle) × speed
vy = sin(angle) × speed
The same pair of operations drives mouse aiming, enemy facing, orbital motion, turret rotation, and fields of view. A sine or cosine with time as its input also creates periodic motion: a hovering object can use base_y + sin(time) × amplitude without storing a separate up/down state machine.
World Space and Screen Space
Physics should use world coordinates. Rendering uses screen coordinates. A camera is an offset between them:
screen_x = world_x - camera_x
screen_y = world_y - camera_y
The player can therefore remain near the centre of the screen while their world position continues increasing through a larger map. UI elements deliberately skip this transformation; a health bar at (20, 20) belongs to screen space, not the game world.
Mixing these spaces causes familiar bugs: collisions shift when the camera moves, projectiles spawn at the wrong place, or a HUD scrolls off-screen with the level. Coordinates are not merely numbers; their coordinate system is part of their meaning.
Rectangles and Collision
An axis-aligned rectangle is defined by its left x-coordinate, top y-coordinate, width, and height. Its right edge is x + width; its bottom edge is y + height. Two rectangles overlap when neither lies completely to the left, right, above, or below the other.
This primitive provides the first practical collision model. A platform is a rectangle, a player has a rectangular body, and a moving player must be moved back to the nearest non-overlapping position after contact. More complex shapes build on the same model: circles add radius, polygons add edges, and physics engines automate the same geometric questions.
The Working Set
Vectors describe movement. Delta time stabilises it. Normalisation controls magnitude. Trigonometry joins direction and rotation. Transforms separate world and screen space. Rectangles establish collision. These concepts form the shared substrate of the Ruby2D notes that follow.