SamSuka
drjavi
drjavi

patreon


2mino devlog

Here's how I programmed my 2mino game, which you can find in my new itch.io account. I recommend that you read my U235 devlog first, since there I explain some basic concepts that I will use again here.

Again, the first function we need is Start, which first pre-saves all texture coordinates for the symbols and their borders - this lets us update them very quickly whenever needed, instead of having to calculate them again every time. Then we build the samples board, which shows all isolated pairs and whether they have been found or not. To save time between games, we give it enough symbol cells to play even at the highest difficulty level, 13x12 cells. This takes more RAM, but that's fine, even our cell phones have more than enough RAM for that. We also need the background and separators of the sample pairs, and here's when things get tricky.

To keep things simple, let's assume that we're always playing in landscape mode - most of the times, whatever goes for landscape mode, applies in reverse to portrait mode. To keep things tidy, the two boards are arranged vertically, filling the height of the window, and as far apart horizontally as possible. Mathematically, the number of different pairs of N symbols that can be formed is Nx(N+1)/2; since each pair contains two symbols, both boards will need twice that many cells: we'll arrange them as N+1 rows and N columns.

The background and separator of a sample pair is actually a single object which lies behind one of the symbols, and rotates to accommodate both vertical and horizontal pairs. If N is odd, the pair samples are arranged vertically; if N is even, they are arranged horizontally - this allows us to fit them all neatly in our (N+1)xN board.

If the pairs are horizontal, only the left symbol of a pair owns the background, which means that only the symbols in even positions in every row will have a horizontal background (remember that, in code, the first position is the 0th, so that one's even too). However, if the pairs are vertical, only the upper symbol of the pair owns the background, so only the symbols in even positions in every column have a vertical background. To summarize:

This lets us save time and RAM, giving backgrounds to all the cells that can have them and knowing that some will become visible/invisible, while others will rotate.

The game board, with which the player can interact, contains the same amount of symbols as the samples board. However, while the sample backgrounds were just two rectangles (the background itself and the separator), each game cell owns two irregular hexagonal bars - a vertical one on the right side and a horizontal one underneath, although the ones at the edges of the board aren't shown.

We also build a matrix to store the status of each pair, as the number of times it has been found in the game board - when all these numbers are 1, all pairs have been found and the game is over. For N symbols, if we place the higher value of each pair first, we will have pairs 00, 10, 11, 20, 21, 22, ..., N0, N1, N2, ... NN. Sorting the pairs like this (bigger value first) lets us optimize how much RAM we need and how to quickly find each pair within the matrix:

Finally, the function prepares the graphics for the victory screen, with little symbols orbiting the cursor. These will remain hidden until they're needed. Start also calls the populate function.

The populate function fills up both boards with as many pairs as needed, depending on the difficulty level. First, it clears the pair status matrix and resets all bars and sample backgrounds. The sample board is then filled up with pairs, based on what we said before: if N is odd, the pairs are arranged vertically; if N is even, they are arranged horizontally. The tidiest arrangement I found is this:

Allow me to gloss over the actual calculation of the value of every cell, because it's kind of a mess:

After this matrix is copied to the sample board, we have to shuffle it for the game board. First, we just swap all pairs around, to random positions, rotating some of them 180º. Then, we go all over the board, looking for square groups of pairs we can transpose. Any time we find one, starting at size 2x2, all the way up to NxN (using only even sizes, as there's no way to arrange pieces inside odd-sized squares), we transpose them with a 50% chance. This makes our game board random enough to be unpredictable.

After shuffling, we lock the board edges so we don't mistake them as clickable bars. We also lock a few random separation bars to serve as hints for the player. To decide how many bars we'd lock, I applied some Algorithmics and calculated that N²/4 was a pretty solid amount - I could explain that calculation, but that would double the length of this post. One that's done, we clear up all bars that are not locked and copy the whole thing to the game board. Finally, populate calls a reposition function to check the window size and device orientation and see if the boards have to be resized, transposed and/or relocated. This function is also called when the device rotates. I also made a clear function that just resets the board by turning off all unlocked bars and pair backgrounds.

Let's now see the Update function. It first checks if all pairs have been found; if so, it handles the victory animation, making the symbols we prepared earlier appear and orbit the cursor. Otherwise, it checks where the cursor is relative to the game board: if the cursor is between two cells vertically or horizontally, the corresponding separation bar lights up. If the player clicks or taps a bar, the bar changes its status using a changeBar function, which we'll see in a moment. The Update function also highlights a pair if the user right-clicks the bar between its symbols, and calls reposition when the device rotates.

The changeBar function has to check what pairs are formed or broken when the player clicks on a bar. Every bar could be cutting a previous pair in half or restoring a previously bisected one; every bar could also be one of the borders of 6 different pairs, and we must check them all (although, if a pair is detected, we can safely discard any other pairs on that side of the bar, because they would overlap). A pair is detected when all its six outer bars are active and its middle one isn't.

When changeBar confirms that a pair appeared or disappeared, it calls an updateCounter function. This extracts the actual symbols of the pair that is formed or broken, and updates their counter in the optimized matrix we made before. If the counter becomes 1, the corresponding sample pair should be highlighted green; if it's 0, the highlighting is removed; and it it's higher than 1, it should be red. To find where a pair is in the samples board so we can recolor its background, we apply the same calculation that we used when filling up the board, in reverse: to locate a pair (a, b), with a less than or equal to b:

And that would be the whole 800+ lines of code. Hopefully I can post shorter devlogs as I develop other bigger games. Let me know in the comments if you have any questions about the program.


More Creators