A lot of the comments I’ve gotten on Planet Jumpers have revolved around the procedural generation. It’s not surprising, the game has a lot of RNG (for better or worse).

In this post I’m going to briefly cover how the planet map in the “explore” phase are generated!

If you haven’t played Planet Jumpers yet, you can check it out here!

planet jumpers explore.png

Before we get too far, it’s important to know that every planet is generated with the following properties:

  • Planet radius
  • Gravity
  • Biome
  • Atmosphere Toxicity
  • Distance from galaxy center

When a player lands on a planet, and successfully passes the crash phase, the game generates a new map to explore. These maps are generated using the random walker algorithm. Essentially the game takes a point in the map, and walks in a certain direction until it hits a maximum “distance”. At this point it picks a random direction and starts moving that way. This repeats over and over, until you end up with a set of coordinates that, in this case, correspond to “walkable” space for the player.

In order for each of these maps to be even more diverse, the game alters the presets for the algorithm based on a few planet properties. The overall dimensions of the map passed to the algorithm is equivalent to the current planet’s radius multiplied by 4 and rounded down. For example, a planet with radius of 20 would have a map dimension of 80x80 tiles. The algorithm needs to know how many tunnels it should take before returning the result, the game generates this by picking a random number between the dimension times 0.75 and the dimension times 4. The max length of each tunnel is then randomly picked between 2 and 20 tiles. The last thing the algorithm receives is a random point somewhere on the tilemap to start. With this information, it generates a map of open vs blocked tiles.

Here is the code, which is probably more readable than my explanation:

var dimensions = int(floor(Game.currentPlanet.radius*4))
var maxTunnels = int(floor(rand_range(dimensions*.75, dimensions*4)))
var maxLength = int(floor(rand_range(2,20)))
var map = generateMapOpen(dimensions)
var currentRow = randi()%dimensions
var currentCol = randi()%dimensions

Now that the game has a map, it calculates how many fuel pickups it should place. It does this by taking the atmosphere toxicity of the planet, multiplying it by the radius of the planet, and diving it by 2.25.

var numberOfFuel = Game.currentPlanet.atmosphereToxicity * Game.currentPlanet.radius / 2.25

This isn’t a perfect solution, and has been a main point of difficulty for new players. The calculation for fuel could definitely be improved. The 2.25 is simply a number that after trial and error I felt fit well on average.

These fuel pickups are then placed by randomly selecting walkable points on the map.

Maps can also contain shield repair kits for the ship. These are also a rather simple calculation. It takes a random number 0-4, it then subtracts 1 if ship health is already over 3, and subtracts another 1 if the current planet’s atmosphere toxicity is less than 50% of the maximum possible.

It then places the repair kits (if any) randomly in walkable spots around the map.

The third item that is then placed around the map are “air pockets”. These are weird growths on the ground that when stepped on give the player oxygen. These are generated by rounding down the planet’s current atmosphere toxicity, adding 3, and then picking a random number between that and 0. The code looks like this:

var numberOfAirPockets = randi()%(3 + int(Game.currentPlanet.atmosphereToxicity))

It then places these airpockets randomly around the map on walkable spots. Additionally these air pockets are colored to match the general atmosphere color of the planet’s biome (the same color you see when crashing in the background).

The last bit that is generated for the map, is where to place the player. Since the player has just crashed, it must create a large area for the ship itself to be, and the player to be next to. To do this, the game finds a random walkable spot on the map, and creates a square of walkable space around it. It then places the player and ship in the center. Additionally the game ensures that this new area of walkable space is fully enclosed so that the player cannot walk out of bounds. This code is not very pretty, but got the job done for me:

# make sure we dont open an out of world path
for x in range(playerStart.x-9, playerStart.x+5):
	for y in range(playerStart.y-7, playerStart.y+7):
		if $TileMap.get_cell(x,y) < 0:
			$TileMap.set_cell(x,y,closedTileIdx)

# make space for crash zone
for x in range(playerStart.x-6, playerStart.x+2):
	for y in range(playerStart.y-4, playerStart.y+4):
		$TileMap.set_cell(x,y,openTileIdx)

Overall, the RNG for the maps is pretty straightforward. If I continue working on the game (highly likely), I will probably overhaul the system to something more interesting. I’d like it to ultimately be easier on specific planets and more difficult on others, but I would also like it to feel fair to the player. Right now a lot of the player’s progress is based on luck, and picking the right direction to walk. I’d like to somehow guide the RNG to make it always “possible” to win utilizing the correct strategies.

Stay tuned for more write-ups on the development!