Circle packing is such a fantastic effect, it looks infinitely complex, while also being mathematically beautiful. In this tutorial, we’re going to create a circle packing effect… Interestingly, this is a good example of an effect that isn’t particularly efficient to run, but at the same time, will still be very quick!
As usual, we’re going to begin with a small, clean canvas. We will also set the size of the canvas and adjust it based on the user’s device pixel ratio, or pixel density. This ensures that the final result is crisp on all monitors.
Now, I’m going to explain a little about our process, so we know which variables we will need. You’ll be able to see here that it’s not the most efficient, but it really gets the job done.
Our steps will be:
So, we have an array of
totalCircles, a min & max
circleSize and a
createCircleAttempts. Let’s get this in code.
Now we will spec out our process. We will make a
doesCircleHaveACollision function, and then fill it in with our goals… including calling the
createAndDrawCircle function once for each of our
This is the fun part, we can go through our functions and fill them in. If we tackle this in a step by step way, it will flow out really well.
First, we’ll start with creating a circle object, we’ll give it an
y and a
Now, we’ll add it to our list of circles, and draw it… we didn’t really need to do this just yet, but being able to see what we’re coding render out really helps with the process.
Awesome, and there we have it, tiny circles all over our screen. Next, we can look at growing them. We will do this 1 unit at a time, and when they collide, we’ll take one step back, and break out of the loop.
Wow, what a mess we’ve made! Of course we know the reason for this. Currently our
doesCircleHaveACollision function always returns
false … we’ll need to fill that in.
The way that we tell if circles have a collision, is a little bit of trigonometry. We’re going to loop through each of the circles that are drawn and compare them to the current circle being drawn. If their radii combined, is greater than the distance between each of their centers, then we know there’s a collision.
To get the distance between the two center points, we will use
pythagoras' theorem (whoa, that high school math coming in handy!)
Almost there! But another small gotcha, when we’re creating our circles, there’s also a chance that they’re appearing inside others.
We’re going to use a loop in the creation area now as well, its a little inefficient to randomly guess positions, but really at the end of the day, unless we were doing millions of circles, we won’t see any slow down.
If the circle doesn’t find a safe place to draw, the attempt is abandoned.
Wow, now we’ve got some beautiful circles, all packed in! There’s only one little step more to do, and that is to trigger a collision when they hit the wall as well as each other. We’ll break that into two if statements, one checking the top and bottom, and one checking the left and right.
And there we have it! It’s not the prettiest code, but it’s a great example of how some complex things can be reasoned out, thought about, and stepped through with relative ease & a little math.