Beautiful Algorithms 3: Gravity
This series of articles explores using basic physics and mathematics to simulate balls bouncing. The examples are written with Ruby and Shoes.
I’ve been working on the 2D version of the previous example for 3 days now, and I haven’t got it to a point where it’s clear enough yet. However, I realised I was trying to cram too much into one article. Instead, this part focuses on explaining vectors, and simulating gravity. Although simulating gravity is simple for this simulation, I think you’ll be surprised by how naturally the balls bounce.

Vectors and Vectors in Ruby
A vector is just a direction of a force. They’re usually drawn as a line with a direction. More generally, vectors are quantities that are made up of components. In the previous article, arrays were used to represent direction and velocity. This is adequate, but not as natural as vectors when used with mathematical operators:
[1, 2] + [8, 2] => [1, 2, 8, 2]
If you’re used to mathematics, this result might surprise you. What we want is:
[9, 4]
However, the + operator in Ruby treats arrays like sets and concatenates them. This is generally the most intuitive thing to do. What we need is a way of defining vectors.
Vectors are essentially matrices, and Ruby has a matrix library in its standard library. Vectors are defined like this: Vector.[](1, 2) and can be added, multiplied, and more:
require 'matrix' v1 = Vector.[](1, 2) => Vector[1, 2] v2 = Vector.[](8, 2) => Vector[8, 2] v1 * -1 => Vector[-1, -2] v1 - v2 => Vector[-7, 0] v1 + v2 => Vector[9, 4] v2 * 0.1 => Vector[0.8, 0.2] v2.r => 8.24621125123532 v2.inner_product v2 => 68
Advantages
This makes the code in the previous example clearer, because inverting velocities and updating position becomes much clearer:
@position += @velocity * @mass
@velocity = ((@velocity * -1) * @eta)
These expressions update both the X and Y values for the position and velocity. The second will be used to simulate bounces off the wall.
Gravity
To model gravity, the Y component of the velocity vector will be updated for each frame of animation:
@velocity += Vector.[](0, @gravity)
This looks suspiciously like it will result in infinite speed, but because the overall space the ball can move in is so small we can ignore this for now.
Wall Bounces
I’ve been very explicit about detecting bounces against the “walls” of the scene. Each wall is checked (because the ball could hit two at the same time), and if a bounce has occurred the ball is moved back to the wall. This is in case it bounces through the wall in cases where it’s moving very fast. The bounce_off_wall method just uses the velocity vector multiplication described above.
if @position[0] >= @app.width - (@radius * 2)
@position = Vector.[](@app.width - (@radius * 2), @position[1])
bounce_off_wall
end
Scene Management and Keyboard Commands
My example adds some methods for creating random balls with different velocities and mass, and it also adds keyboard commands for reset (r) and adding a new ball (a).
Putting it Together
Get ball-gravity.rb from my GitHub repository shoes-ball and run it with Shoes.

