First of all, the game itself is up at gamejolt, kongregate, and our own site. If you want to try it out, you can play it at one of these places:
When you play the game on our own site it looks like this:
Your objective is to swap neighboring blocks such that they build chains where the value difference between one block and its neighbor +1 or -1 and the amount of blocks in the chain is at least 3. After a chain is assembled, all the blocks in it are destroyed, the remaining blocks fall down to fill the holes and new blocks are spawned in the remaining empty slots. Players receive points depending on the amount of blocks destroyed, being capped at 100 if the player manages to destroy 9 blocks in the same move. This scales non-linearly, so it’s important to try and build long chains instead of many small ones.
The game ends when there are no more moves possible that would connect a new chain. To give an example for the chains, in the following image (taken from the tutorial), the blocks 4,5 and 6 make a chain as soon as you swap the 4 with the block below it, but combinations like 4->5->4 or longer chains like 1->2->3->2->3 work as well.
The following blog post goes into various aspects of the development of this game, and I will give a journey through the various implementation stages the game went through, right from prototyping to final release.
When I initially kicked some game ideas around in my head, I had a clear goal in mind: Since I had not yet completed any actual games, the game should be very limited in scope, to make sure I can actually complete it. After playing 2048, I thought that surely there must be an infinite amount of things you can do with that kind of number game setup. And soon enough, I had conjured up a simple prototype using Löve2D, and I gave myself a time window of one month to bring the project to completion. The goal was to publish the game after the given deadline, even if things remained that could be improved. A major motivation was to get an idea of the impact a strict deadline has on the design and implementation process. The rest of this blog post will describe this process and hopefully dispense some wisdom for the interested reader.
First of all, let me give you a rundown of the various versions the game went through during development.
The total development time up until the final version (minus some hotfixes after “1.0” was pushed to the master branch) was about 6 weeks. At first I implemented a simple prototype in Löve2D, which was created to test if whatever I had in mind actually was any fun to play:
And indeed the gameplay had some charm to it. While it certainly wasn’t the most complex game, it was on some level mesmerizing to kick off a chain of reactions and observe the blocks engage in their little dance. I quite liked the prototype and it seemed to fit the scope I was looking for.
After the port was done I spent a week just fiddling around with some variations to the gameplay formula. For example, I reworked the game into a version where you had a much bigger grid of blocks, where destroyed blocks weren’t replaced by new ones.
Various goal states were possible, such as destroying as many blocks as possible before a timer ran out, or before there were no possible moves left on the board.
However, the original concept remained the one that I stuck to. It seemed simpler to grasp for new players and the alternatives didn’t add anything particularly mind blowing to the formula, so I decided to keep it simple.
The following week was spent on overhauling the look of the game, as I didn’t want to expose the eyes of innocents to the spartan programmer art look of the prototype. With some assistance of fellow company founder and artist in training Alexander I came up with something that was already very similar to the final version:
The two main colors of green and silvery-gray are inspired by some internal mock ups of our startup’s logo that I’d seen, and seemed to fit the “calm&tranquil” feel of the game I was going for.
Then, a week before the initial date for final release, it was time to release the game as a beta to a close circle of family&friends. Feedback was mostly positive, and with the help of the testers we uncovered many browser-compatibility related bugs that could be fixed before release of the final version. I was actually quite surprised by the amount of feedback I received. Almost every tester gave some form of feedback, mostly in the form of bug reports, but also in the form of suggestions for the game itself, some of which made it back into the game.
I spent the remaining time until the planned release date by implementing a simple banner ad at the bottom of the page, as well as Twitter & Facebook share buttons, which was much simpler than expected. I also added the current tutorial, and buttons for resetting the score and going back to tutorial mode.
Shortly before what would’ve been the release date of December 3rd, I realized that I wasn’t happy at all with the pixelated look the game received on some devices. The initial versions were sometimes quite tiny on devices with large resolutions on small screens, so my response was to scale the contents of the site to cover an appropriate amount of the browser window. But on some devices, particularly maximized desktop browser windows (where 1080p resolutions are standard by now) or tablets with large screens but low internal resolution, the blocks themselves as well as the rendered text looked a bit too pixelated for my taste, as can be seen in the following screenshot:
So I pushed back the release date by a week so me and Alexander could give the visuals another pass. The final result, of course, is what the game currently looks like, smoother looks and all:
Design (and its failings)
While the game design remained the same since the earliest versions of the prototype, its biggest problem could only be felt after more extensive play testing in the later stages.
What I’m talking about is luck dependence. For me, a perfect game is designed in such a way that a skilled player always performs better than a bad player. In 9blocks, a player who patiently decides to plan ahead instead of blindly connecting the first chain possibility they see will consistently make more points than a worse player. But this doesn’t protect them from being eliminated from a single game by sheer bad luck. The result here is a setup that is very similar to card games like Poker, where playing well gives you better results in the long run, but single games can often seem to depend entirely on luck.
The reason for this is the following: The fact that blocks fall down before new ones are spawned on top means that the bottom two rows of the board tend to converge on a stagnant state where no chain connections are possible. It’s possible to keep this from happening to a certain degree, by carefully considering your moves and trying to keep a healthy mix of numbers embedded in the lower rows, trying to work down favorable blocks from the top of the board without destroying them. But this can not be prevented all the time, eventually resulting in a situation where the only thing which can rescue you is a favorable series block spawns in the top rows of the board.
This is perhaps my only regret with how I handled the development of the game. The week where I tried around various spin-offs derived from the original formula should probably have been spent brainstorming and implementing ways to get rid of the luck dependency problem.
In the visual department, one thing I wasn’t able to solve was to find a way to visually assist the player in finding chains. I brainstormed some ideas, such as using various different block shapes or colors to maybe make use of some of the brains ability to pre-consciously recognize features, but none of them panned out. Particularly the idea of featuring different shades of green for the numbers seemed promising at first, but after actually implementing and testing it, I saw that it looked plain ugly and didn’t really help much at all.
The problem here is that our visual system is mainly good at classifying and associating groups of things in our view, while the things 9blocks requires can’t be grouped very well. I could shade 1, 2 and 3 in the same color to signify that these shades of green can make a chain, but this would break any possibility of assisting the player in finding chains containing the numbers 3,4 and 5. Also, it’s better for the player’s score if they try to connect long chains. All ideas I was able to come up with only seemed to assist the player in quickly finding shorter chains. After a while I just had to drop the concept of visually assisting the player since I was running out of time.
Thanks to its simplicity, the layer of tech for the game is pretty minimalistic as well. It uses pixi.js for rendering and tween.js for juicing up everything that moves. I also use howler.js for the background song, but after picking and licensing the song, after some play time I noticed that it just doesn’t seem to fit the game and is somewhat distracting after longer play sessions. For this reason I decided to leave it disabled by default, and the user now has to activate it intentionally by clicking on a button in the bottom left of the canvas. I have to admit that the music is only left in the desktop browser version because I feel bad for picking an unfitting song and paying money for it.
Also, on mobile devices the sheer added download size (just over 1mb for the .aac and 500kb for the .ogg versions. AAC is required on some platforms which don’t understand ogg) proved very bothersome to the loading times of the game when using cellular data connections, so I simply removed audio from mobile versions completely.
Overall I was pleasantly surprised with the state of HTML5 availability and canvas/WebGL performance on various browsers and devices. The vast majority of builds I tested just ran identically on all browsers out of the box. The cross-browser issues I found were mostly minor and fixes were found quickly thanks to Google and sites like StackOverflow. I do think some bugs probably remain on some browser configurations, such as the various default browsers that get shipped with many Android devices. I have found and fixed some incompatibilities regarding these during development, but unfortunately, with the variety of devices, OS and browser versions out there, it’s hard to get full coverage in a small beta like the one I ran.
Of course there remains the question of why I chose to go the HTML5 route at all. I chose it mainly because it seemed like an easy way to have a fully cross-platform game without the relatively long deployment & testing cycle that I get with native apps. In addition, a browser version of the game for desktop users was crucial to me. When I started the project I knew of many frameworks which handle cross-platform development between mobile and desktop applications very well, but I didn’t want to force desktop users to install a desktop app to play the game. I was also aware that for most mobile users it’s a preferred option to install an app from the Google Play Store or the App Store once and play it using the native application, so I felt like I had to make a choice and decided to go with HTML5.
Unfortunately I was entirely unaware that there exist frameworks like Cocos2d-JS (which I will use for my next project), which neatly abstract away the platform difference almost entirely, and allow deployment to web & native apps with few changes to the code base. It would also be possible to package 9blocks into native apps using frameworks like CocoonJS, but preliminary research into these has revealed that it wouldn’t be trivial and would require some implementation time that I do not have. So this game remains web-only for now. Which isn’t meant to imply that this is somehow a bad option, of course, as the game is perfectly playable from the browser and the total download size for mobile users amounts to merely 300 kilobytes.
Regarding development process, coding style and software architecture
From past experience, I had the strong impression that software architecture actually matters very little in one-man projects of limited scope where you know the entire code base inside out.
Taking care of properly abstracting things to minimize the code you need to touch when implementing changes nets you not much or no time at all when the code to be abstracted in question is only used in two or three places in the code base. And small projects are often full of code that is in fact only used one single time. Abstraction in these kinds of projects also yield no code that is easier to understand, since you already know everything anyways. I felt that the time taken to implement proper abstractions doesn’t warranty the time you win working on the code vs. “dirty” code.
Knowing this I went into this project with the conscious goal to keep the software architecture simple and the call stack as flat as possible. Surely enough, over the course of development the code changed quite a bit: The initial HTML5/JS port, although completely playable and pretty much finished gameplay wise, weighed in at 600 lines of code, and grew to 1500 in its current form. This and the many bug fixes during course of development gave me plenty of opportunity to put my theory to the test. Would I be hindered by my reliance on “throwaway”-style code?
It turns out not at all. The experience of working on the code has been extremely pleasant. Knowing the entire code base made it possible to identify the causes of bugs and places where I would need to implement changes for new features almost immediately, and working on data in-place instead of following it down various levels of abstractions made debugging a very swift experience. Adding new code was done in a quick and dirty manner, but the “dirty” didn’t weigh in negatively, so all that was left were quick, testable results. In short, it felt like the amount of boilerplate code I had to work on was absolutely minimal, and the code lines I touched almost always had a direct result on the end product. A satisfying experience to say the least.
There was also no formal development process methodology used during the development of this game. I did cut up the 1 month of time I gave myself into the parts mentioned in the version history part of this blog, which was certainly tremendously helpful, but otherwise the methodology could only be described as “highly agile”. I kept a to-do list of bugs and features that were left to implement, and pretty much arbitrarily picked things to work on based on my current mood. This worked out very well as I never felt like something in the surrounding process beyond coding the game itself was keeping me from getting things done, which I think is what development processes try to fix.
Overall, I do not regret the way I approached it at all and would encourage others to engage in a similar style for small projects, as long as you work under similar conditions to mine.
Overall I’m pretty happy with how development played out. Even though I didn’t work full time on the project, and had to juggle several other of my masters degree projects and lectures on the side, I was able to (mostly) stick to the original timeline. I’m also satisfied with how the game turned out. Although it is by no means perfect, it is enjoyable and I’ve certainly learned a lot from the experience.
Also, on a last note, if you have any feedback, or wishes, or bug reports regarding this blog post or the game itself, make sure to mail them to social [[at]] pitforest.de, it would be much appreciated!