Butterly Wings Flap to Pi

It’s Pi Day, and to celebrate I thought I’d write a small article on Pi (π). While I’m not a mathematician or a physicist, π does still crop up in game development. So here’s a small example of how I use π to create great looking butterflies.

The Code


The designs I create for the butterflies in Bok’s Banging Butterflies wouldn’t look so great in game if the butterflies didn’t move. So I had to create some nice animation that would allow them to flap their wings and add vibrance to the world.

To do this I used the mystical knowledge known as mathematics! The wing animations are fairly simple, using a few mathematical tricks to get them to animate. I’m going to talk about the maths in this article, but to start with I’ll show you the whole animation code, and will go through how it works below.

    /**
     * Create a flying animation
     * @param entity The butterfly entity
     * @param limbSwing Unused
     * @param limbSwingAmount Unused
     * @param ageInTicks The current age of the entity in ticks
     * @param netHeadYaw unused
     * @param headPitch unused
     */
    @Override
    public void setupAnim(@NotNull Butterfly entity,
                          float limbSwing,
                          float limbSwingAmount,
                          float ageInTicks,
                          float netHeadYaw,
                          float headPitch) {

        // The angle that the body rests at.
        final float BODY_REST_ANGLE = 0.7853982f;

        // The speed at which the body "hovers".
        final float BODY_MOVE_SPEED = 0.1f;

        // The arc through which the body moves.
        final float BODY_MOVE_ARC = 0.15f;

        // The arc through which the wings travel.
        final float WING_ARC = 0.25f;

        // The speed at which wings flap.
        final float WING_SPEED = 1.3f;

        //  When landed wings don't flap.
        if (entity.getIsLanded()) {
            this.body.yRot = BODY_REST_ANGLE;

            // Moths hold their wings flat.
            if (entity.getIsMoth()) {
                this.right_wing.xRot = 0.15F;

            // Butterflies raise their wings up.
            } else {
                this.right_wing.xRot = (0.15F - Mth.PI) * 0.5F;
            }
        } else {
            this.body.yRot = BODY_REST_ANGLE + Mth.cos(ageInTicks * BODY_MOVE_SPEED) * BODY_MOVE_ARC;
            this.right_wing.xRot = Mth.sin(ageInTicks * WING_SPEED) * Mth.PI * WING_ARC;
        }

        this.left_wing.xRot = -right_wing.xRot;
    }

The first thing this function does is to create a set of constant values. The comments above describe what each constant does, but I’ll give more detail on each as we move through the code. So let’s dig into it, line by line!

Landed Butterflies


Next, the code checks to see if the butterfly (or moth)1 is in the Landed state. Depending on their Diurnality, butterflies will try and land at certain times of the day. When they do land, their wings will no longer flap.

        if (entity.getIsLanded()) {
            ...
        }

If they are landed, their bodies will not be hovering, so we just set the angle to the BODY_REST_ANGLE defined at the beginning of the method.

            this.body.yRot = BODY_REST_ANGLE;

Next we check if the butterfly is actually a moth. If it is then we set the angle of the wings so that they lay flat against the surface they are on. We don’t set the angle to 0 as this would make the wings stick out to the side and still be away from the surface. Instead we angle them down slightly, so the tips of the wings actually touch the block. This makes the moth looks like it is actually resting the wings on the surface it landed on.

            // Moths hold their wings flat.
            if (entity.getIsMoth()) {
                this.right_wing.xRot = 0.15F;
            }

If they are not, then we have our first actual use of π! Originally I had the wings pointing straight up from the body, but this looked unnatural. This short calculation gives us wings that are angled slightly, touching at the tip. This makes them seem closed together, rather than simply attached to the body.

            // Butterflies raise their wings up.
            } else {
                this.right_wing.xRot = (0.15F - Mth.PI) * 0.5F;
            }

In order to understand this calculation, we need to understand radians. Radians are just another way of measuring angles. You might be used to measuring angles in degrees. You know that 90 degrees is a right angle, 180 degrees rotates to face backwards, and 360 degrees rotates in a full circle until you get back to the same direction.

Radians work in exactly the same way, except they use a different scale based around π. Instead of 360 degrees to do a full rotation, 2 * π radians form a full rotation (so around 6.28 radians). π radians (around 3.14 radians) are the same as 180 degrees, and half π radians (0.5 x π radians or around 1.57 radians) is the same as 90 degrees.

Minecraft’s animation code uses radians, so when I set the angle of the moth’s wings above, it wasn’t 0.15 degrees, but 0.15 radians. This is equivalent to around 57 degrees.

Since radians are based on multiples of π, I can use π in the calculation to give the angle of the wings. Wings stick out to the side by default, so the angle we want is -90 degrees, or -(0.5 x π) radians. I.e. -Mth.PI * 0.5F as it would be written in Java. But, we also want an offset so the tips of the wings touch. We already know from the moths that 0.15 will angle the wings so they go the whole length of the body, so all we need to do is halve that value and we will get wings that angle to the midpoint of the body.

Thus our final equation for landed butterflies is (0.15F -Mth.PI) * 0.5F, giving us butterflies that look a bit more natural when they land on a block.

Body Motion


If butterflies are not landed, they need to flap their wings to stay in the air. The next part of the code handles the animation for these flapping butterflies. The first line doesn’t actually do anything to the wings, it actually animates the body of the butterfly:

            this.body.yRot = BODY_REST_ANGLE + Mth.cos(ageInTicks * BODY_MOVE_SPEED) * BODY_MOVE_ARC;

As you can see, the animation is based off the BODY_REST_ANGLE with a modification based on the current time. ageInTicks tells us the age of the entity in ticks, Minecraft’s way of measuring time. Minecraft updates the state of the world 20 times every second2; these are known as ticks. So the age of an entity in seconds would be ageInTicks divided by 20.

What’s important here is we use this value to animate the butterfly over time. But we don’t want to use an ever increasing value to figure out what the angle should be. Instead, we take the cosine of this value, giving a value between 1 and -1. Using this we get a number we can use to create a looping animation that moves back and forth.

In order to control the speed of the animation, we need to modify the time. Within the cosine function, we can multiply ageInTicks by some value to adjust this speed. I multiply it by the value of BODY_MOVE_SPEED, or 0.1, meaning the animation will move at 10% of the speed it would if we just used the number of ticks.

Finally, we want to get a useful value out of the calculation. I don’t want a value between 1 and -1, I want a much smaller angle. I multiply the output of the cosine function by BODY_MOVE_ARC, or 0.15, meaning that the final value will be between 0.15 and -0.15.

Now the butterfly’s whole body will rotate by 0.15 radians3 up and down as it flies through the air. This makes the butterfly feel more dynamic, as if the wings are pulling it up slightly every time they flap. Speaking of wings…

Flappy Butterfly


The animation of the wings works in the same way as the body for the most part, except we use sine instead of cosine:

            this.right_wing.xRot = Mth.sin(ageInTicks * WING_SPEED) * Mth.PI * WING_ARC;

The reason we use sine is so that it is the opposite of the body’s animation. When the body is using -1, the wings will use +1, and vice versa. What this does is set the wings to be up high when the body is low, and at the bottom when the body is high. This gives the impression that the wings are lifting the body every time they flap.

The last piece of the calculation is that final Mth.PI * WING_ARC, the other instance of the animation’s use of π. Remember that π radians is equivalent to 180 degrees. With this equation the wing will flap through an arc of around 25% of the full 180 degrees. It’s just an easy way of giving an arc that feels right and looks nice when you see it.

What About the Left Wing?


You will notice that all the code above only calculates the angle of one wing. We could calculate the left wing as well, but we already know it is just going to be the opposite of the right wing. So I can do all the calculations and set the other wing’s angle with a single line:

        this.left_wing.xRot = -right_wing.xRot;

There’s no reason to do the right wing first. I could have calculated the left wing’s animation and set the right wing here instead and it would make no difference to the end result.

The Curious Case of the Hummingbird Moth


The only other use of π in the animation code is due to a very special moth. The Hummingbird Moth has it’s own model, and by extension, it’s own animation. However, the code for this animation is very similar to the base butterfly, as you can see here:

    /**
     * Create a flying animation
     * @param entity The butterfly entity
     * @param limbSwing Unused
     * @param limbSwingAmount Unused
     * @param ageInTicks The current age of the entity in ticks
     * @param netHeadYaw unused
     * @param headPitch unused
     */
    @Override
    public void setupAnim(@NotNull Butterfly entity,
                          float limbSwing,
                          float limbSwingAmount,
                          float ageInTicks,
                          float netHeadYaw,
                          float headPitch) {

        // The angle that the body rests at.
        final float BODY_REST_ANGLE = 0.2853982f;

        // The speed at which the body "hovers".
        final float BODY_MOVE_SPEED = 0.1f;

        // The arc through which the body moves.
        final float BODY_MOVE_ARC = 0.15f;

        // The arc through which the wings travel.
        final float WING_ARC = 0.2f;

        // The speed at which wings flap.
        final float WING_SPEED = 13.0f;

        this.thorax.xRot = BODY_REST_ANGLE + Mth.cos(ageInTicks * BODY_MOVE_SPEED) * BODY_MOVE_ARC;
        this.right_wing.yRot = Mth.sin(ageInTicks * WING_SPEED) * Mth.PI * WING_ARC;
        this.left_wing.yRot = -right_wing.yRot;
    }

The main difference is that the Hummingbird Moth doesn’t have a landing animation. Other than that it sets the body and wing animations in the same way, only using different values. Namely, the body is angled more horizontally, and the wings flap at ten times the speed over a slightly smaller arc.

This gives it the look and feel of a hummingbird, just as it’s real-life counterpart, the hummingbird-hawk moth.

Happy Pi Day!


While Pi Day might be best known for tasty pies and mathematical trivia, it’s also a great reminder of how deeply π is woven into the fabric of our world, even in game development. From guiding the flight of butterflies to controlling their wing movements, π helps bring these creatures to life in a way that feels natural and immersive.

At its core, game animation is about using math to create something that feels right, even if players don’t consciously notice the numbers at play. Whether it’s the gentle hovering of a butterfly or the rapid flaps of a hummingbird moth, π is working behind the scenes to make it all possible.

So, as you celebrate Pi Day, just remember that every time you see a butterfly fluttering gracefully through your Minecraft world, it’s π that’s helping it take flight!

  1. Everything in this article applies to moths as well as butterflies, but to avoid saying “and moths” every time I’ll just refer to butterflies. ↩︎
  2. This can be different if commands are used to change it, or if you are playing on a server with extreme latency. But for our purposes we’ll stick to 20 ticks per second. ↩︎
  3. Remember, the game uses radians, not degrees. ↩︎

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.