Published on February 27, 2019 under the tag haskell
This weekend, I finished a silly little game in PureScript called Beeraffe. You can play it here and view the source code here. In this blogpost, I want to give some more background information on how this game came to be.
If I was going to build a game, I knew I wanted it to be web-based – there was no doubt in mind about this:
- It makes it much easier to show it to other people; you can just share a link and they can be playing it in seconds.
- It is inherently cross-platform, and with a little bit of extra attention it easily works on smartphones as well.
- It is a good sandbox; you don’t need to ask people to install arbitrary executables on their system.
The big advantage of using GHCJS is that you’re able to run Haskell on the backend and on the frontend, so you can share common code.
I did not consider Elm because it’s a bit further removed from Haskell, and my main focus was still building a game; not learning a new language. I have heard a lot of good things about it though, so maybe that’s what I should try next.
Original inspiration for the game
Inspired by Katamari Damacy, I wanted to make a 2D version that had a similar feeling to it. I decided relatively quickly that the core mechanic of the game would be to put different kinds of objects together in bizarre ways, hopefully amusing people along the way.
Putting sprites together
With that in mind, I immediately focused on this core mechanic since I wanted to know whether it could actually be fun or not.
I started by doing a simple exhaustive search over all the ways you can overlay two sprites, minimizing the average colour distance. This worked remarkably well, and I didn’t end up fine-tuning the results much more after that.
It did lead to some performance issues for larger sprites, so I fixed that by mipmapping: for larger sprites, I first do an exhaustive search at a much lower resolution, then I use these results to do a local search in that neighbourhood at higher resolutions. This is not guaranteed to give the best results; but that doesn’t matter too much for this game: we just want a good enough result.
I wanted to also try an approach based on simulated annealing but didn’t get around to it. If someone wants to try this, you’re more than welcome to make a contribution!
At this point, I was getting amusing results, but I wasn’t sure how to make this into a game yet. I didn’t want to make it into action game, and felt like a puzzle game would fit better. Then, I realized the comedic effect would be even better if I combined the names of the different sprites as well.
This automatically adds a sort of puzzle mechanic to the game as well, since you can now only merge certain objects.
This brought me to the next obstacle – I knew I would need a large number of consistent sprites to use as art in the game. I browsed around opengameart.org for a bit, but did not really find anything promising. I also did not want to pay an artist, because I wanted to keep this a free game, without advertisements and the like.
Then it dawned to me that there already is a great collection of consistent sprites that even come with the names attached to them – emoji! I found the free EmojiOne set and started with that. But when I looked into it a bit, I found this weird snippet in their free licensing info:
3.4 What can’t you do with the JoyPixels/EmojiOne Properties under this agreement?
(I) Include properties in open source projects.
What nonsense is this? I am allowed to use it in my non-commercial project if I give attribution, but not if I want to have the option to open source my game?
This pissed me off and I started looking for alternatives. At that point, however, I already knew emoji were a good direction so it was easier. I ended up switching to Google’s Noto font. I liked the sprites a little bit less but at least the license made sense.
Making it a real game
At this point I built a demo that simply allowed you to drag around a bunch of different objects and merge them. It was certainly amusing, but it did not really feel like a “game” to me yet. However, I shared this demo with a couple of people and they all really liked it. This was very encouraging.
The next weekend, I tried to turn this into a Tetris- or 2048-like puzzle game, but this ended up being very confusing and not that much fun. Ironically, the non-game was more fun!
So, I decided to go back to that and just add a very simple economy on top of it (buying and selling things) to make it a bit more interesting. After I added that, I was quite happy with the flow of the game.
The rules were still a bit unclear to people I showed it to (what things can you merge together?), so I added the hints at the top of the cards and an interactive tutorial.
Closing thoughts on PureScript
In retrospect, I am happy with PureScript as a language and would recommend it if you’re looking into putting a simple no-backend web-based game together, and you already know Haskell.
There were a few issues I ran into with the language:
I still prefer lazy languages, and this bit me a few times. In particular, I wrote a few monadic recursive functions without being aware of the tailrec package. This caused stack overflows in my code, but I only saw these on my phone, which made it extremely hard to debug.
The error messages that the compiler emits are horrible at times. I feel like this is an area where I could contribute a bunch of code myself, but I’m not sure if I’ll ever have time for that.
There are also a lot of things I like:
Halogen is an amazing framework that made building the UI trivial.