A Fruity Game Made with Löve

Like the rest of the world, I have been getting excited about procedural generation. I thought it might be fun to make a simple Pac-Man-like game to feature an infinitely generated maze. I chose to work in Lua within the LÖVE2d framework to keep pushing myself to learn new languages. I’m finding that the more graphical output I do in different languages, the easier I find it to identify and exploit the commonalities.

The Maze Part

My first step was to do a bit of research into procedurally generating a very simple maze. Wikipedia led me to depth-first search as a good starting point for my first maze-making/pathfinding algorithm. Unfortunately, the Rosetta Code example available for Lua was really unwieldy - it had four required scripts, the output wasn’t exactly what I wanted, and it used a stack method to draw the maze, which seemed really complicated. The Python script, on the other hand, was MUCH more readable and comfortable for me. I worked with another programmer to port that simple script over to Lua, and got something closely resembling the Python output. So here’s my starting point, generated from Lua in about 70 LOC:

Starting Point - a console text output maze

Next step was to convert this console text output into something graphical. Rather than fuss with skinny walls/fat walls/corners, I opted to have every character in the text represented by either a 32x32 square or a 32x32 void. The maze generation now makes a table of width rows by height columns containing all “true” values. The pathfinding algorithm then goes through using dfs and punches a trail of “false” values according to its rules. Finally, I added an “add falses” function, which randomly chose some “true” values from the resulting table and punched them out to “false”, creating more geometric interest and gave the player more choice in exploring the maze.

Graphical maze output

The Art Part

As a personal challenge to myself, I did not do any drawn artwork or spriting for this project. I often find that I use my art as a crutch in game making to cover for lazy programming or a less-than-solid command of my programming tools. I knew I wanted to create a character with some prizes to pick up in the maze, and I thought that making some fruit using LÖVE2d’s draw functions would be fun. And what needs fruit except a fruit bat?

Procedural berries I made three kinds of berries from the same code, which involved implementing a class system in Lua. The code randomizes the qualities of 16 “pips”, or the little circles the berries are made of. The jitter allows for slight variations of each pip’s size, location, and color, and I really like the effect.

Blueberry I made a blueberry from circles and polygons, and set the primitives to be a stencil. I then drew a square using a gradient library that got masked through the shape I defined with the stencil.

Magical Colorshifting Apple To add something really special and rare, I made an apple of primitives and used a fun color shift shader.

Batty And finally, I made an adorable little bat to walk around the maze. His only animation is the highlights on his eyes, which shift around depending on what direction he’s moving.

One of the neatest things to me about this art is that because it is being drawn in real time by the program using math, it would be easy to scale this and have it still look nice and crisp at 2x or even 10x the size.

The Moving and Collision Part

This was without a doubt the most painful part of this project for me. I initially had a sliding movement that just added or subtracted to the player’s coordinates depending on the button pressed. This worked alright, but had an annoying quality around the edges or openings of the maze. The collision detection was making it hard to line the batty up accurately so that you could slip through an opening. I tried Many Things to address this irritating quality:

My actual solution ended up being a step of 32 pixels (taking part of my first attempted solution), and adding a tweening library to smooth the movement and address the “too fast” issue. Getting the tweening library working was agonizing - I found a promising library on the LOVE2d forums, but the most recent version from GitHub ended up not working for me (not sure why, possibly a version issue or a bug). I eventually got it working when I unzipped an older demo .love and found a different version of the tween.lua library. After that headache came the challenge of getting tweening to work correctly with the batty, keypresses, and collision. The upshot is that after all that, I had a tweening library ready to go for the next step of my project.

Infinite Levels, Infinite Score

I knew I wanted to have an infinite, zen feeling to this little game. I created a score bar with a dual tracking functionality (the bar fills with color as you near the next level, and the text on top of the bar tells you your accumulative points so far). I could have opted for just a ginormous maze, but I think it’s more fun to feel like you’ve exhausted a level, and then move on the next. I was inspired by Stardew Valley’s mines and by Crypt of the Necrodancer’s leveling in that when you have collected a certain number of points per level, we do a level transfer step where a trapdoor opens up, the batty falls through, and you get a new level of the maze to explore. I used the tweening library that I finally felt like I had a handle on to animate the trapdoor and the batty’s movement into it. Lastly, the score is saved locally every time you move to a new level, so when you restart the game, you’ll start with your previous score.

High Scores

Lastly, I implemented a high scores table using webscript.io. This appears on the splash screen of the game and can be accessed any time by clicking anywhere in the game window. So long as your score is greater than zero, you can submit your name (well, six characters of your name), and your current score. The program sends the score to webscript.io, which returns a truncated top-ten list in descending order. Finally, we take that data, turn it back into a Lua table, and print it out for the player to see. This was my first experience with decoding JSON and working with HTTP GET/POST methods, and I was really glad to have someone helping me out on this last feature.

An early screenshot of the high scores list

Final Thoughts

Overall, this was a great first project to complete in Lua/LÖVE. My experiences with some 3rd party libraries were painful, but very educational. I am really proud of how this looks and plays, despite its simplicity, and I’m thrilled I did it without resorting to my familiar habits of Python/CodeSkuptor and/or drawn artwork. I’m also pleased that I didn’t succumb to too much feature bloat while working on this (the high scores table was my only moment of weakness). The distribution step that I was worried about went smoothly, as well.

Go play it, post your score!

If you have LÖVE 0.10.1, click HERE to download.

If you don’t have LÖVE, click HERE to download a .zip file with the game.exe inside.