Posted by on Nov 30, 2016 in Blog | Comments

In January of 2016 I challenged myself to make 1 new game every month, for a year; 12 months- 12 games. This is one of those games.

Development Stats

  • Language: Lua
  • Engine: Pico-8 Fantasy Console
  • Platforms: Web/Pocket Chip

This month was an extremely slow start. I didn’t actually start working on the game until about day 20 of 30! I had some computer problems at home, and I used that as an excuse to veg-out for a couple weeks 😀

With only 10 days left, I decided (once again) to focus on something simple. In this case, an endless falling game with a simple objective of avoiding the walls for as long as possible:

The final version of the game.

The final version of the game.

The game is mostly procedural. As the player descents, a path is generated. This happens every time the camera reaches the bottom of the existing path, with old parts of the path being discarded as the go off the top of the screen. The path is stored as a series of [X,Y] coordinates (nodes) in a list. The path starts as a line straight down the center of the screen, and branches from there. Each node is offset a fixed amount in the Y direction, and a random (but limited) amount in the X direction. This creates a somewhat random zig zag pattern while ensuring that the path is always navigable by the user.

The generated path.

The generated path.

The darker line that runs down the center of the cavern is actually a 1-to-1 match to the procedurally generated path. In the image above, I have added Red Arrows pointed to each segment of the visible path.

Here’s a really early version of the game, which already shows the path in a more debuggy way.

A very early version of the game.

A very early version of the game.

That generated path represents a ‘safe route’ for the player to take, but I still needed to generate the walls which the player needs to avoid. This is done simply by, for each node in the safe route, generating new nodes directly left and right of it. The offset from the safe route is simply a random number between 8 and 32. So in the most difficult case the path is 16 pixels wide (8x the width of the players hit box of 2 pixels), and in the easiest case, the path is 84 pixels wide.

xwide=32
 xwide_min=8

add(path,
 {newx,lasty,
 rnd(xwide-xwide_min)+xwide_min,
 rnd(xwide-xwide_min)+xwide_min})

How wide or narrow the path becomes is totally random! There is no logic to make sure you don’t get all super tight walls, or to ensure moments of respite after a challenging series of winding walls. But just due to the nature of RNG, those patterns emerge, or at least feel like the emerge.

pico-8_196

Things can get pretty hairy!

The only logic use to control difficulty is a sequence of speed modifiers that get applied based on the number of meters fallen:

1m-199m: 1x
200m-499m: 1.5x
500m+: 2x

To ensure the path is still navigable at higher speeds, the speed modifier is also applied to the player’s controls. So as you fall faster, you move left and right faster too.

And how do I know these random levels will always be possible to navigate to begin with? Well, just random guess work to be honest, and a lot of playtesting; as seen here when I played so long I found out that the game has a kill screen after about 10,000 meters!

Kill screen == Retro street cred

Kill screen == Retro street cred

So, head over to the link below, give Talos Descent a shot and post your highscore with the other players in the comments section!

System Requirements