Vector Math Basics: From C64 to Python
By Michael Doornbos
- 11 minutes read - 2131 wordsVectors show up everywhere in programming—games, graphics, physics simulations, robotics. But the math behind them is surprisingly simple. If you can add and multiply, you can do vector math.
Even AI runs on vectors. Large language models represent words as vectors in high-dimensional space—hundreds or thousands of dimensions instead of just two. Words with similar meanings cluster together: “king” and “queen” are nearby, “cat” and “dog” are neighbors. The famous example: take the vector for “king,” subtract “man,” add “woman,” and you get something close to “queen.” Vector arithmetic captures meaning.
Our brains can’t visualize anything past three dimensions—four-dimensional space is already impossible to picture. But the math doesn’t care. A 768-dimensional vector works exactly like a 2D one: addition is still component-by-component, scaling still multiplies each component. Learn it in 2D where you can see it, and you’ve learned it for any dimension.
Let’s start from scratch and build up the concepts with working code you can type in right now.
What’s a Vector?
A vector is just a pair of numbers that describe a direction and distance. Think of it as an arrow pointing somewhere.
In 2D, we write a vector as (x, y). The x tells us how far to go horizontally, the y tells us how far vertically. The vector (3, 2) means “go 3 units right and 2 units up.”
That’s it. No magic.
The key insight: vectors describe movement, not position. The vector (3, 2) means “move 3 right and 2 up” regardless of where you start. Start at (0, 0) or start at (100, 50)—the movement is the same.
Adding Vectors
Want to combine two movements? Add the vectors component by component:
(3, 2) + (1, 4) = (3+1, 2+4) = (4, 6)
Visually, you place the second vector at the tip of the first:
Follow red (A), then blue (B), and you end up at the same place as the green dashed line (A + B). That’s vector addition—combining movements.
Subtracting Vectors
Subtraction works the same way:
(5, 7) - (2, 3) = (5-2, 7-3) = (3, 4)
This is useful for finding the direction from one point to another:
If you’re at position (2, 3) and want to reach (5, 7), subtract to get the vector (3, 4)—that’s the direction and distance you need to travel.
Scaling Vectors
Multiply each component by a number (a “scalar”) to make a vector longer or shorter:
2 * (3, 2) = (6, 4) Double the length
0.5 * (3, 2) = (1.5, 1) Half the length
-1 * (3, 2) = (-3, -2) Reverse direction
This is how you control speed in games—multiply a direction vector by a speed value.
Vector Length (Magnitude)
How long is a vector? Pythagorean theorem:
The green line is the vector. The dashed lines show the right triangle formed by the x and y components. The vector (3, 4) has length $\sqrt{9 + 16} = \sqrt{25} = 5$.
That’s the core of 2D vector math. Let’s put it to use.
Why Old Computers?
There’s real value in running these examples on vintage hardware (or emulators). Modern computers finish drawings instantly—you type TREE 150 and the tree just appears. On a C64, you watch every line get drawn. You see the turtle walk the vectors, see the recursion unfold branch by branch, see exactly how the algorithm builds the image.
That slowness is a feature, not a bug. When you can watch the process, you understand it. Once it clicks, you can move to faster systems. But for learning? Give me a 1 MHz machine any day.
Commodore Logo: Vectors the Natural Way
Logo’s turtle graphics are inherently vector-based. The turtle has a position and a heading. FD 50 adds a vector of length 50 in the current direction to the turtle’s position.
If you have Commodore Logo (or any Logo interpreter like UCBLogo or Calormen’s browser-based Logo), try this. Commodore Logo d64 disk images for use with VICE or other C64 emulators can be found in the TOSEC C64 collection on Archive.org.
TO TRIANGLE
FD 60
RT 120
FD 60
RT 120
FD 60
RT 120
END
TRIANGLE
Each FD 60 creates a vector of length 60 in the turtle’s current heading. RT 120 rotates the heading for the next vector. Three vectors, three 120° turns = 360° total rotation, which brings us back to our starting heading.
In Cartesian terms, if the turtle starts facing up:
- Vector 1: (0, 60) — straight up
- Vector 2: rotated 120° → roughly (52, -30)
- Vector 3: rotated another 120° → roughly (-52, -30)
Sum ≈ (0, 0). The triangle closes because the vectors sum to zero—any closed polygon works this way.
Here’s a more explicit vector demonstration in Logo. We switch to DOUBLECOLOR mode first—the default SINGLECOLOR mode only allows one color per 8×8 pixel cell, so overlapping lines would overwrite each other’s colors. DOUBLECOLOR trades some horizontal resolution for proper multicolor support:
DOUBLECOLOR
TO VECTORDEMO
; Draw vector A (red)
PC 2
FD 50
; Save position
MAKE "MX XCOR
MAKE "MY YCOR
; Draw vector B (cyan) from end of A
PC 3
RT 60
FD 40
; Save final position
MAKE "FX XCOR
MAKE "FY YCOR
; Go back to origin and draw resultant (yellow)
PU
HOME
PD
PC 7
SETXY :FX :FY
END
VECTORDEMO
The turtle starts facing up (heading 0°). FD 50 draws vector A straight up—a vector of (0, 50) in Cartesian terms. Then RT 60 rotates the heading 60° clockwise, so the turtle now faces 60° east of north. FD 40 draws vector B in that direction.
How do you pick the angle? Logo headings work like a compass: 0° is north (up), 90° is east (right), and RT rotates clockwise. If you have a Cartesian vector (x, y) and want the turtle to face that direction, the heading is the angle measured clockwise from straight up. A vector pointing right and slightly up (like (3, 1)) needs a large RT turn from north; a vector pointing mostly up and a little right (like (1, 3)) needs a small one. The FD distance is the vector’s length: $\sqrt{x^2 + y^2}$.
We save the final position in FX and FY, then return home and draw a straight line to that final position (yellow)—that’s the resultant vector A + B.
Logo makes vector addition physical: walk one path, then another, and the direct route from start to finish is their sum.
For another fun use of Logo, check out Robin’s Monte Carlo Pi estimation—using random vectors to approximate π by throwing darts at a circle.
Python with Turtle Graphics
Python’s turtle module is a direct descendant of Logo. Let’s implement our vector operations:
import turtle
import math
def draw_vector(t, vx, vy, color="white"):
"""Draw a vector from current position"""
t.pencolor(color)
t.pendown()
# Calculate angle and distance
angle = math.degrees(math.atan2(vy, vx))
distance = math.sqrt(vx**2 + vy**2)
# Turn to face the direction and move
t.setheading(angle)
t.forward(distance)
def vector_demo():
screen = turtle.Screen()
screen.bgcolor("black")
t = turtle.Turtle()
t.speed(3)
t.pensize(2)
# Starting position
t.penup()
t.goto(-100, -50)
start = t.position()
# Vector A = (80, 60)
ax, ay = 80, 60
print(f"Vector A: ({ax}, {ay})")
draw_vector(t, ax, ay, "red")
mid = t.position()
# Vector B = (60, -30)
bx, by = 60, -30
print(f"Vector B: ({bx}, {by})")
draw_vector(t, bx, by, "cyan")
end = t.position()
# Result vector from start to end
rx, ry = ax + bx, ay + by
print(f"A + B: ({rx}, {ry})")
t.penup()
t.goto(start)
draw_vector(t, rx, ry, "green")
# Label
t.penup()
t.goto(-100, 100)
t.pencolor("white")
t.write(f"Red: A=({ax},{ay}) Cyan: B=({bx},{by}) Green: A+B=({rx},{ry})",
font=("Arial", 12, "normal"))
screen.mainloop()
if __name__ == "__main__":
vector_demo()
The draw_vector function (lines 473-482) converts a vector (vx, vy) into turtle movements. It calculates the angle using atan2 and the length using the Pythagorean theorem—that’s the magnitude formula from earlier.
Lines 497-514 demonstrate addition: draw A (red), then B (cyan) from where A ended, then go back to start and draw the sum A+B (green) directly. The green line ends at the same point as following red then cyan—visual proof that vector addition works.
A Practical Example: Bouncing Ball
Here’s where vectors become useful. A bouncing ball has:
- A position vector: where it is
- A velocity vector: how fast it’s moving in each direction
import turtle
import time
def bouncing_ball():
screen = turtle.Screen()
screen.bgcolor("black")
screen.tracer(0) # Manual screen updates for smooth animation
ball = turtle.Turtle()
ball.shape("circle")
ball.color("yellow")
ball.penup()
# Position vector
px, py = 0, 0
# Velocity vector
vx, vy = 3, 4
# Screen bounds
width, height = 300, 200
while True:
# Update position: new_pos = old_pos + velocity
px = px + vx
py = py + vy
# Bounce off walls (reverse velocity component)
if px > width or px < -width:
vx = -vx
if py > height or py < -height:
vy = -vy
# Apply position
ball.goto(px, py)
screen.update()
time.sleep(0.016) # ~60 FPS
if __name__ == "__main__":
bouncing_ball()
The physics here is pure vector math:
- Position (px, py) is a vector describing where the ball is
- Velocity (vx, vy) is a vector describing how it moves each frame
- Each frame: position = position + velocity (vector addition)
- On wall collision: multiply one velocity component by -1 (scalar multiplication)
Lines 561-563 do the addition: px = px + vx and py = py + vy. Lines 566-569 handle the “bounce” by negating velocity components. That’s it—two vector operations power the entire simulation.
Drawing with Vectors
Let’s draw a spaceship using vectors, just like the classic arcade games:
import turtle
import math
def draw_ship():
screen = turtle.Screen()
screen.bgcolor("black")
t = turtle.Turtle()
t.color("white")
t.speed(0)
t.pensize(2)
# Ship defined as vectors from center
# Each vector is (dx, dy) from the previous point
ship_vectors = [
(0, 20), # Nose
(-15, -25), # Left wing
(5, 10), # Left indent
(10, 0), # Bottom
(10, 0), # Bottom (continued)
(5, -10), # Right indent
(-15, 25), # Right wing back to nose
]
# Start position
t.penup()
t.goto(0, -20)
t.pendown()
# Draw by following vectors
for vx, vy in ship_vectors:
x, y = t.position()
t.goto(x + vx, y + vy)
# Draw it again, rotated 45 degrees
t.penup()
t.goto(100, 0)
t.pendown()
angle = math.radians(45)
cos_a, sin_a = math.cos(angle), math.sin(angle)
for vx, vy in ship_vectors:
# Rotate vector by angle
rx = vx * cos_a - vy * sin_a
ry = vx * sin_a + vy * cos_a
x, y = t.position()
t.goto(x + rx, y + ry)
t.hideturtle()
screen.mainloop()
if __name__ == "__main__":
draw_ship()
The ship is defined as a list of vectors (lines 602-610). Each vector describes the movement from one vertex to the next. The loop at lines 618-620 draws by adding each vector to the current position: t.goto(x + vx, y + vy).
Notice these vectors also sum to zero—(0,20) + (-15,-25) + (5,10) + (10,0) + (10,0) + (5,-10) + (-15,25) = (0,0)—so the ship is a closed shape.
Lines 630-635 show rotation: each vector (vx, vy) is transformed using sine and cosine. The rotated ship at position (100,0) uses the exact same vectors, just rotated 45°. This is how Asteroids worked—store the ship once, rotate mathematically for any orientation.
Vector Rotation: A Sneak Peek
You might have noticed the rotation code in that last example. Rotating a vector (x, y) by angle θ:
$$x' = x \cos\theta - y \sin\theta$$$$y' = x \sin\theta + y \cos\theta$$
This is the foundation of all 2D rotation in graphics. We’ll dig deeper into rotation matrices in a future post, but now you’ve seen them in action.
For Kids: Scratch
If you’re teaching vectors to younger learners—or just want a friendlier environment—Scratch is fantastic. It’s a visual, block-based programming language from MIT where you drag and snap code together like LEGO.
Scratch sprites work just like Logo turtles: they have a position (x, y) and a heading. Blocks like “move 10 steps,” “turn 15 degrees,” and “go to x: y:” are vector operations in disguise. Kids can build bouncing ball simulations, draw shapes, and experiment with movement without typing a single line of code.
The concepts transfer directly. Once they understand that “move 10 steps” adds a vector to the sprite’s position, they’re ready for Python, Logo, or anything else.
Going Further
We’ve covered the basics:
- Vectors as (x, y) pairs representing direction and magnitude
- Addition: combining movements
- Subtraction: finding the path between points
- Scalar multiplication: controlling speed/scale
- Magnitude: the length of a vector
From here, you could explore:
- Normalization: making a vector length 1 (unit vector)
- Dot product: finding angles between vectors
- 3D vectors: just add a z component
- Matrix transformations: rotation, scaling, shearing
But for games and basic graphics, what we’ve covered will get you surprisingly far. Movement, collision detection, physics—it’s all just adding and scaling vectors.
Happy vectoring!