Poker Poker Magic (Puyo puyo-like)

Hello everyone!

While working on improving my map editor for DuckBlur, I decided to port and finish an old game of mine. It's a Puyo Puyo-style puzzle game with somewhat poker rules. Falling blocks are cards, and you need to match 3 or more of a kind, create a straight, or achieve a flush to make them disappear.

Here's how it currently looks:
masterful

The story unfolds in a school of card tricks. You can play as either Caroline, a lively but clumsy girl who needs to master magic tricks to avoid failing her exam, or as her bird, Columbus.

The game experiences some lag on devices when the boards are full. I didn't expect to have to optimize a puzzle game, but the number of sprites is increasing fast :sweat_smile:.

11 Likes

I made some profiling and the main slowdowns were caused by the high number of sprites (up to 87 per side + 6 layers for the background + 6 for the magic ball) and by the earthquake effect when chips are sent by the opponent.

I found a way to optimize those two points at the same time: when a card is placed in the board, I now remove the sprite and draw its image on the board itself. That makes the number of updated sprites way lower.

Here is the game showing only the card sprites for the left player. Cards are removed when they reach the ground:
only cards

Earthquakes are also much faster now because only one sprite is moving instead of more than 50 at the same time.
all

It was a bit trickier to handle the disappearance of a card. I have to clear the image from the board and every other cards on its top and add the corresponding sprites back in the sprite list.

Here is the game showing only the board sprite. You can see how row of cards disappear during a combo:
only board

An other thing I did was to flatten the background to 2 layers but it didn’t changed anything much.

1 Like

Before each battle, the characters talks in short dialogue scenes. As these scenes will represent a significant part of the game, I wanted to include support for multiple languages in the game system. I expected encoding issues (and wasn't disappointed!), so I wanted to incorporate this early in the development.

In English, no surprises, everything displays correctly:
english

However, I started encountering some display issues with accents in French. I noticed that the len argument of the method playdate->graphics->drawText(const void* text, size_t len, PDStringEncoding encoding, int x, int y) is in fact not the number of bytes to display but the number of characters. So when I passed strlen(line) (i.e. the buffer length), it displayed a few extra characters.

Fortunately, I have some knowledge of UTF-8, and was able to quickly write a method to count the number of characters in a sentence:

uint32_t MELUTF8StringCodePointCount(const MELChar * _Nullable source, int length) {
    if (source == NULL) {
        return 0;
    }
    uint32_t count = 0;
    for (uint32_t index = 0; index < length && source[index] != '\0'; index++) {
        const uint32_t entry = source[index] & 0xFF;
        if (entry <= 127) {
            // ASCII
            count++;
        }
        // isUTF8Wagon is ((source[index] & 0xFF) >> 6) == 2
        else if (entry >> 5 == 6 && isUTF8Wagon(source, index + 1)) {
            // 2 bytes
            count++;
            index++;
        } else if (entry >> 4 == 14 && isTrailedByCountUTF8Wagon(source, index, 2)) {
            // 3 bytes
            count++;
            index += 2;
        } else if (entry >> 3 == 30 && isTrailedByCountUTF8Wagon(source, index, 3)) {
            // 4 bytes
            count++;
            index += 3;
        } else {
            // Encoding error
            playdate->system->logToConsole("Unable to count UTF-8 characters: encoding error, invalid UTF-8 value.");
        }
    }
    return count;
}

french

Supporting Japanese wasn't as straightforward as I imagined.
First problem: the font. Fortunately, others have been there before me. A big thanks to @matt and @hunty for the Japanese fonts.

Second problem: Japanese doesn't have spaces!
In English and French, the text reflow was handled by looking for the next space or the end of the sentence. If the displayed text size + the next word exceeded the width of the screen, the word would move to the next line. But in Japanese, it displayed nothing because the sentence didn't fit in width. So now, I display letter by letter when the language is Japanese.

The len argument also took its revenge! Naturally, the one in playdate->graphics->getTextWidth(LCDFont* font, const void* text, size_t len, PDStringEncoding encoding, int tracking) is also in the number of characters and not in the number of bytes, but I had forgotten to modify the code here as well >_<

japanese

1 Like

This looks great! Good variation on a theme. Makes me want to make a tetris/puyo puyo variant.

1 Like

This week, my focus was on developing a grid view component to handle menus.

Since the game is made in C, using the Lua implementation from CoreLib wasn’t possible. I had 3 choices: find a C library for this, port Panic code to C, or build one from scratch. I chose the latter because it didn’t seemed that hard (spoiler: I was wrong). Maybe you have already read this meme: "We do this not because it is easy, but because we thought it would be easy". That’s exactly me right now.

So here it is, in various use cases:

  • a row of save files
  • the new game form (which will be gone soon)
  • a story selection grid

navigation

I also tried to replicate how scrolling works in the system. If you keep pressing a button, it will keep scrolling after a little delay:

scrolling

I still need to implement sections to make it possible to have rows with a custom column count.

The current result is a bit ugly though. Design is next.

You don’t know how much I respect the team doing menus in Persona games. They could make a game with nothing other than menus and I would still buy it.
I have to start playing Persona 5 to study how they make menus both look and feel fantastic!

This is a bit of fun

1 Like

I started playing Persona 5 Royal. The game menus are really well-designed, I love them. However, I didn't have enough time to think about menu design or code this week.

Fortunately, I was still able to make progress. I tried GarageBand on iOS during my commute, and I was pleasantly surprised. It is full-featured and very capable. For Kuroobi, I used a MIDI keyboard (Roland FP-10) alongside the macOS version of GarageBand to create the music, but the virtual piano on the iPhone screen was good enough to work.

I wrote a few tracks. The forum doesn’t allow attachment of mp3 files so I will look for an other way to share them.

Music creation isn't my specialty, but I find it very enjoyable. It feels great to start by humming something and later to have a 'real' version of the track.

The Kuroobi soundtrack was my first composition. Listening to Cabel explain the process of composing the B360 theme in the Playdate podcast made me want to try and write something as well.

I'm glad I tried. Thank you, Panic!

1 Like