Detecting the Perfect Circle ⭕

One of the interesting problems we faced when programming Bunny Wrangler was adding the ability to determine what the player had outlined. We had decided to only recognize circles as it simplifies the problem a lot, and because we wanted to make it western themed, so it made a lot of sense for a lasso.

gameplay.gif Figure 1: Bunny Wrangler gameplay

I have already somewhat answered this as a comment on the game, but I figured I would post it here too with some more information as people seemed to like it!

Detecting a circle

Perfect circles always have the distance from the center to the outside edge the same length. I figured I could use that fact as a simple test for our case. But what's the best way to figure out the center of our list of segments? The segments in our rope are just some points in space.

I started of taking the average point of all given segments. This worked pretty well in most cases as seen in Figure 2.

averageempoint/emgood.png Figure 2: Average point represented by the big red dot

One big flaw I ran into, is that because of limited frame rate, the average point would shift dramatically based on the player mouse speed. Notice the segment sizes on the left vs right in Figure 3.

averageempoint/embad.png Figure 3: Average point (red dot) shifted all the way left

So instead I wanted to find a way to find the center that doesn't rely on the segment sizes. Eventually I ended up calculating the bounding box of all the segments. This gives a way better center point for our use case. It's the big green dot in Figure 3.

Now we have a good center point, the next step is to figure out if the segments are roughly the same distance away from the center. I'm keeping track of the minimum and maximum distance. In the case of a perfect circle, these values should equal. minimum / maximum = 1

circle_calculation.png Figure 4: Calculating the minimum and maximum distance from the center

In practice, these minimum and maximum values never equal. But we can see how close we are by dividing these values. The result of this can be compared against some threshold that we experimented with. In case of Figure 4, it would be roughly:

minimum = 175 maximum = 210 circleness = 175 / 210 = 0.8333

A higher than 0.8 we consider a Perfect Circle in-game. So the shape in Figure 4 we would consider as one. Because we have a value that approaches 1.0, we can give more points depending on how well a circle was made. Values closer to 1.0 are generally better circles without much variation from the center.

circleemcalculation/emtriangle.png Figure 5: With a big difference between minimum and maximum, the shape is likely not a circle!

minimum = 75 maximum = 258 circleness = 75 / 258 = 0.2907

Anything lower than 0.6 we don't consider circle enough. So it correctly doesn't approve the shape in Figure 5. We couldn't be too strict with the thresholds as it would be frustrating to play. This results sometimes in non-circular shapes being approved, but I think in most cases they take more effort compared to a normal circle.

circle_wrong.gif Figure 6: Wrong shapes being detected

This isn't a perfect solution, but I think it works very well for our case I think. Especially with the huge time pressure, I'm happy I could come up with something that worked so well. How would you have solved this? Are there any other (better) ways I'm not aware of? I'd love to know! :cowboy: