Almost reached the next level

Would that I could truthfully say that I spent a whole lot of time on ts-breakout this week. Alas, I was busy putting out various work related fires and in setting up a new home server to replace an old one. A fun diversion to be sure, but not very game related. As such please excuse the (extra) excruciatingly bad pun title of this week’s installment.

Now, just because I didn’t spent a ton of time doesn’t mean I didn’t spend any. The task at hand was to implement a method for being able set up custom brick layouts. In general this task was particularly easy because I have already made various changes in the code and how it hangs together with this particular exercise in mind.

Starting at the end and working our way to the beginning, ts-breakout now has the ability to set the brick grid up using any brick layout that you want to give it. Within the constraints of the size of the brick grid, it is possible to set up any layout of any color brick (which includes no brick at all, the most deceptive color there is) desired.

While this functionality is now in place, I still need to spend a bit more time actually coming up with some level layouts themselves. The way everything is currently structured, it will be trivial to either set the levels in any particular order or just randomly choose one. I even have an idea regarding having variants of the created levels which are partially played for use in an attract mode similar to the one that I implemented in ts-tennis.

At it’s core this is very simplistic; the BrickGrid.reset() method can now take an optional layout parameter that describes the brick layout (if none is provided, the default debug layout is used instead). The brick layout is set up such that each row of bricks is an array of strings that represent what brick color to use, with the layout being made up of an array of such brick rows. I’ve assigned simple single character strings to the various brick colors in order to make the layout nicer to look at.

Arguably since the bricks are always going to be in rows, this could be an array of strings instead, with one character per brick. However, I have nascent plans for the upcoming exercise in which we set up special bricks or bricks with powerups in them (or both) and so I went this was so that it will be possible to just inline the special brick data along with the color information with a minimum of parsing fuss.

By far most of the time I spent on this particular operation was in experimenting with TypeScript and it’s “type” feature. What I have ultimately ended up with is this:

type BrickColorString = " " | "1" | "0" | "R" | "O" | "Y" | "G" | "B" | "P";
type BrickRow = Array<BrickColorString>;
type BrickLayout = Array<BrickRow>;

The actual brick colors are stored in this enumeration:

enum BrickSpriteColor

I was going for a cross between type safety and readability, and an array full of things like BrickSpriteColor.BLACK did not appeal. Fortunately as we can see in the BrickColorString type we are able to tell TypeScript that types of this value have a constrained set of potential values, which allows for some compile time checking. It then follows that a row is an array of bricks and a layout is an array of rows.

Where I spent a little bit of time here was in checking to see if it was possible to enforce an array length constraint on the type somehow (even in a terrible hacky way). I had to come to the conclusion that it’s not, although this makes sense because it would take a lot of control flow analysis for the compiler to be able to determine that an array was a particular size outside the realm of a constant (which could easily be altered at runtime anyway).

This means that the code that loads the brick layouts can be assured that the strings it gets for brick colors will always be valid, but not that the layout will have the right number (or even a consistent number) of columns and rows, which is a little bit of a bummer from a data integrity standpoint.

As such, the layout loading code takes the lazy approach of essentially using the string data in a cell by cell manner to fill out the grid, padding any remainder with empty bricks. Thus you can provide fewer rows for ease. Where things get confusing is if the columns are too wide or too narrow, but it should be pretty obvious when that happens (even trivial testing should be needed to ensure the layout looks decent, right?) so I don’t forsee the need to do some sort of runtime verification of that.

The only thing that remains now is to create some interesting brick layouts (or just brick layouts, if the interesting part is too hard to come by at the moment). One question I have to ask myself is, is it worth it to spend a bit of time creating a little built in level editor type action as I did for Rx? I’m not 100% sure it would be worth the time.