Our Sokoban implementation is pretty cool, but it has a problem that I’d like to solve in this chapter. We could keep designing our levels with Godot’s visual tools, but there’s a better way to handle procedural content.
In fact, we started down the better path while designing our levels in Sokoban. You might have wondered why we used an obscure grid system when we could draw levels by hand.
It’s because algorithms can use grid-based data like this to render our tiles and nodes for us. All we have to do is find an easier way to define the grid data.
Creating Pixel Art
Creating any kind of art has its challenges, so I won’t pretend to give you shortcuts for it. All I know is that pixel art offers a set of constraints (limit color palette and canvas size) that encourage creativity in me.
There are a bunch of applications you can use to draw pixel art. If you want something free, you can try Piskel. I can also recommend Aseprite, though it’s not free.
Try either, and create a bit of pixel art that is 16 × 16 pixels:
Example pixel layout
Green pixels represent trees.
Gray ones represent rocks.
The orange pixel represents the player.
You don’t have to use the same colors or layout. You’ll soon see how to accommodate different designs and colors.
Converting Pixel Art to a Grid
Let’s open up our experiment project and add a new one for this pixel art code. Import the pixel art image you created and set up a new inherited scene, from the Experiment scene, called PixelsExperiment:
Setting the stage
Pixel art is a grid, by design. We need to use some new code to get the grid data out of the image and into a format that we can manipulate and draw.
Let’s add some methods to do this in PixelsExperiment:
As you can probably tell, I created an enum of the possible types of pixels I have in my image file. I care about the three colors: for trees, rocks, and the player.
I use the enum values as keys for a dictionary that holds the hexadecimal colors of each type. This creates a type-safe lookup for the colors while also being quick to extend with more colors.
We export a Texture2D because it allows for any popular image format to be set through the property inspector. It has a get_image method we can use to get the underlying image data.
This Image class has a get_pixel method, which is what we can use to get the image grid’s pixel data to inspection. get_pixel returns a Color instance, which we can convert to a hexadecimal value.
We can compare the dictionary of colors to the pixel color to figure out what the type of each pixel. This gives us a similar grid to the one we built in Sokoban.
Flipping Layouts
Here’s where things get more interesting. We can take this pixel grid data and manipulate it to create variation. Let’s start by flipping the grid:
Since we have the pixels in a multidimensional array, flipping is a matter of reversing the direction of rows or cells in each row. We can make use of this by passing the layout through this new method:
This is one of many different manipulations possible with this kind of grid data structure. In a couple chapters, we’ll see how useful it can be for generating varied maps.
Combining with Nodes and Tile Maps
Summary
In this chapter, we took our first steps toward designing our levels with pixel art. While converting images to arrays isn't groundbreaking, we can manipulate those arrays in interesting ways.
Take a bit of time to think of other kinds of manipulations we could do to the resulting pixel art grids. Can you think of how to rotate a layout, or how we could vary the drawing of cells to inject a bit of realism and randomness?
In the next chapter, we’re going to dive even deeper into the randomness aspect of content generation, as we gear up to build our next game.