The Complexities of a Jigsaw Puzzle Game
As I've been making my way through the development of a jigsaw puzzle game, I've come across a number of complexities that weren't initially obvious when I started the project. I knew I was going to want to use Bézier curves to draw the edges and the knobs of the pieces. But I hadn't fully thought ahead to how I could make each piece look like a physical jigsaw puzzle piece, or how I could handle what happens when the player actually starts connecting pieces together.
Bézier curves and Jigsaw Puzzle Pieces
Named after French engineer Pierre Bézier, Bézier curves are smooth curves calculated by a set of control points. For jigsaw puzzle pieces, I use them to help draw both the edges and the knobs, using De Casteljau's algorithm. The whole process is driven by templates, and a deterministic random number generator, in order to subtly vary the shape of the pieces. The templates just define the possible ranges that each part of the piece can vary (corner offsets, edge depths, knob position, knob width and height). I'm able to give the puzzle-cutting algorithm a seed value for a given photo, and generate the exact same piece shapes for that photo every time.
What surprised me a little was where the interior control points needed to be for drawing realistic-looking knobs. I ended up placing them in a straight line, parallel to the edge, almost a full piece's distance away. Then I applied small randomized offsets to each one, based on settings from the template.
To ensure connecting pieces always fit together nice and snug, every piece takes ownership of its own top and left edge. Its bottom and right edges are mirrored from the neighboring piece. 🧩
Grid Anchor and Snap Detection
Every puzzle piece needs to have some way of anchoring it. At first, I thought I would use the top-left corner of the piece. But I realized that the top-left position varies piece-by-piece, because of the variation I'm applying to each piece when the photo is cut. It took a lot of mulling about on my part to realize I needed to just anchor pieces to the center of their default grid position. 🤔
This decision naturally led to the easiest solution for snap detection. Every piece has a default size, and a default grid anchor position. As long as the piece(s) the player is dragging are within some tolerance of the connecting piece's edge, they can snap together.
Connected Pieces
Just the other day, I was starting to ponder how I'll deal with pieces that are already connected to each other. This was when I had some of the more surprising revelations about how complex a jigsaw puzzle game can get.
When you're picking up a piece, you might actually be picking up a whole group of pieces. And they all have to move together.
If you want to draw any subtle effects, such as shadows or edge highlighting as a signal that pieces can connect, you have to be really careful about the order that you draw things. You can't have shadows from connecting pieces drawn on top of each other. And if you do any edge highlighting, you have to build an algorithm to march around the outer edge of the pieces. And what if the player connects a bunch of pieces together, but leaves holes in the group. 🤯
So much to think about! At some point, I'll probably get my thoughts together to write up some more formalized articles about the jigsaw cutting algorithm. And later, the rendering algorithm. But for now, I just felt like I wanted to ramble about some of the complexities I've come across so far. 🙃