Recreating the Clefairy Says mini-game in Unity

As I try to complete more projects, I advance my skills as a programmer (at least I think so). That is great. But then I look back on my past projects with a little remorse: I could have designed them much better now than I did back then. There are some things in my past work that make present me blush. But I think that’s a good thing. Otherwise I’d be stagnating in my professional development.

I mention this because after my latest project, I did a lot of studying on clean code. The benefits of it, how to write it, how to spot it, how to avoid it, and how to fix it. I watched a variety of online courses, and read this big beautiful book on Clean Code.

Then I went back to review my game. It didn’t look so good.

I debated refactoring everything, but a few things stopped me: the game worked and was released, so this refactoring would only make things look better under the hood. Not to mention, I’ve moved onto other projects, which I don’t want to delay working on to fix something that isn’t broken. I’d much rather work on getting new projects aligned to my current standards, then to constantly cycle over old projects.

With that in mind, I hope that this project can be the foundation for cleaner code in the future, both for me and for you! If you can spot some things that could have been done better, kudos! (And feel free to tell me what they are – I’d love to know!)

This project replicates one of my favourite games to play growing up: the Clefairy Says mini-game, from Pokemon Stadium on the Nintendo 64. I wanted to replicate it because I wanted to familiarize myself with the Unity Timeline, something I have never used in a project before.

Learning a new skill while recreating a childhood favourite is a surprisingly fun way to do it.

In Clefairy Says, you have to repeat a series of arrow patterns. The arrows are written on a chalkboard, then removed, and you have a short amount of time to recount them. Get too many wrong and you’re out. With each wave of arrow patterns, more arrows are added until the chalkboard is full.

Since the arrow patterns come out in waves, I thought it would be a good idea to make that functionality with timelines. To be honest, that thought faded once I implemented them. I had to create entirely new timelines for each wave, where I thought I could reuse one and just tweak some sort of parameter. Unless I’m very silly and missed some way to do that, I would have much better off coding the waves with co-routines. Regardless, here is my foray into Timelines, and how I used them to recreate Clefairy Says!

Game Scene Set Up

First, I’ll go over my canvas set up. Since the game play revolves around repeating patterns, there really isn’t much that exists outside of them.

I’ve got some text components that make up the headers, as well as some other game objects that contain components for the lives, and the timer for player input The big ticket here is the arrow game objects themselves.

The arrow game objects are made up of an Image component and an Arrow script. The arrow script has a public variable for the KeyCode of the directional arrow, and a function to initialize that along with a corresponding image (to show the directional button to press).

using System;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
public class Arrow : MonoBehaviour
{
    public KeyCode arrowKey;

    public void SetArrowKeyAndUpdateSprite(Tuple<KeyCode, Sprite> arrow)
    {
        arrowKey = arrow.Item1;
        GetComponent<Image>().sprite = arrow.Item2;
    }
}

For neatness, I’ve parented all the arrows to an empty GameObject, and spread them evenly within the canvas. Once I add in the art (created by the talented baeflin), the cute classroom setting comes to life!

A screenshot of the game in the Unity inspector, with the hierarchy of gameobjects on the left.
A screenshot of the game in the Unity inspector, with the hierarchy of gameobjects on the left.

Creating the arrow waves with timelines

So, for every arrow wave we’re going to need two types of timelines: one to show the arrows, and one to show the player’s guesses of the pattern. There’s also an intro timeline for each wave, but since that one doesn’t change from wave to wave, it only needs to be created once. So that’s 11 timelines in total.

For the timelines to show the arrows to press, all I did was create a Timeline and assign it to a Playable Director component on a new game object. After that, I could use the Timeline window to hide and show arrows as I needed to. Once I had all the arrows for the wave visible, I added a Signal Receiver component to the gameobject, and added a Signal Emitter to the end of the timeline. This emitter triggered code in my GameManager class to track the player input.

See how the arrows are visible as the timeline moves? (It's a little sped up)
See how the arrows are visible as the timeline moves? (It’s a little sped up)

I had a similar setup for the timelines that were triggered once the player had guessed the arrows. Each corresponding arrow wave had another timeline, which triggered signal emitters to trigger the movement animation based on what button the player had pressed (Once again, this logic is stored on the GameManager class).

Tying it together

This is where I get a little embarrassed. Most of the logic for this game is encapsulated into one script, as I didn’t refactor anything out into other scripts. It’s a little messy.

Anyway, the timelines are all created and doing their thing. The signal emitters at the end of showing arrow timelines trigger the player inputs, and the timer at the end of the player inputs triggers the end wave timeline. And the signal emitters at the end of the end wave timelines trigger the next wave (or the end screen, if the player beats all waves with any health left).

And when the scene starts, the intro timeline is set to play on awake, so the game begins as soon as the scene starts.

The Intro Timeline's Playable Director component
The Intro Timeline’s Playable Director component

The only thing we haven’t done yet is assign the arrows their values. They need to be assigned at random at the beginning of the game. Also, they don’t change between waves – all the arrows are set, and then the amount shown is increased each wave. Here’s the logic that does that in the GameManager script:

public Arrow[] arrows;

void Start()
{
    SetArrowsToPress();
}

public void SetArrowsToPress()
{
    Tuple<KeyCode, Sprite>[] keys =
    {
        Tuple.Create(KeyCode.UpArrow, upArrowSprite),
        Tuple.Create(KeyCode.DownArrow, downArrowSprite),
        Tuple.Create(KeyCode.LeftArrow, leftArrowSprite),
        Tuple.Create(KeyCode.RightArrow, rightArrowSprite)
    };

    foreach (Arrow arrow in arrows)
    {
        arrow.SetArrowKeyAndUpdateSprite(keys[Random.Range(0, keys.Length)]);
    }
}

I’ve exposed the arrows as a public variable so I can drag them in via the inspector. From there, the SetArrowsToPress function creates the four possible buttons to press. It does this as tuples so the keycode, as well as the image to display on the arrow can be passed as one variable.

Then we just loop through our arrows, and call the function we defined on our Arrow script way up above.

Now, there’s a whole lot of other mess under the hood, mostly relating to animations and receiving the player input, but since this was about using Unity timelines, I’ll end it here.

If you’re so inclined to see the spit and polish, you can dig deeper into the code at the GitHub link here.


I hope you enjoyed this little write-up! If you have any feedback on the game, or any tips on development or this write-up, please let me know!

Feel free to comment below, or contact me on twitter.

Until next time,
Adrian

1 comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s