Making a pinball game for Playdate: Part 04, the image format

Welcome to today’s December adventure, where I will write about the process of our latest game, Devils on the Moon pinball.

One day, as we were scrolling through the Playdate Squad Discord server, Lukas Wolski the dev behind the excellent game Owlet’s Embrace posted the following picture.

Interlaced

Some time ago I wrote my own sprite and primitive blitting routines without using the SDK. I went for the same bitmap format like the SDK: First half of the bitmap buffer black/white pixel data, second half of the buffer transparent/opaque pixel data.

I wondered what would happen if I rewrote my code and texture format to use an interlaced layout, where 32 bits of black/white and 32 bits of transparent/opaque are alternating. You need to read and write both of them for basically all graphics routines anyway. The performance difference depends probably on the size of the bitmaps used (-> distance between b/w and transparent regions in a bitmap).

The very same game scene in my own game went from 35 FPS to 50 FPS. And it all came down to cache misses, stalling the CPU. I use some very big textures here and there btw.

This sounded promising! When we were working on Pullfrog I didn't know a lot about how to measure performance bottlenecks, but even I knew that drawing things on the screen was expensive. If we could get a speed bump by doing our own custom drawing routines, that sounded like a big win!

I can't say I fully understood what Lukas was talking about or why it mattered, but I have heard before that cache misses were important for performance.

Cache miss From Game Engine Architecture by Jason Gregory

Ok good. What is interlacing again? You probably have experienced this on the web.

Sometimes a website image will show row by row of pixels while loading. But other times it would wait until the whole image is loaded. When the image is not interlaced, the browser needs the whole image information to be able to render it. This is because the information about the colors of the pixels and, the transparency is separated. So to show a single pixel, the browser needs to load all the color information and then load all the transparency information.

When the image is interlaced, meaning all the information to render a row of pixels is close together, the browser can render the pixel as soon as it loads that single pixel information.

Ok now that I got that. First I needed to figure out how to convert our .png images to something interlaced that I could then read on the Playdate and blit it to the screen. My first attempt was to convert them to the CHR format I knew my friend Devine was using it for his Nasu sprite sheet editor

I wrote a custom Aseprite exporter for ICN and CHR and BOOM; we have textures in the screen. This was my first time reading/writing a binary format, so it felt like a massive win.

ICN/CHR

Now this didn't assure me that it would be faster to draw than the Playdate's PDI format; not only that, but the restriction of having everything in tiles was something that made sense for the Famicom but not for our game.

With this new knowledge, I started reading Lukas’ code. He shared it on the Playdate Squad Discord server and had his game code on GitHub. I didn't understand the blipping code yet, but thanks to his previous messages in the Discord, I was able to replicate the image format. Once again, I wrote another small Aseprite script and tried it with this code; it worked!

Glitched

Kind of...

A couple of tries later, and it worked!

Grid

We now had physics and a way to draw textures on the screen; we felt over the devil’s on the moon pinball.

At this point, Jp had plenty of time to plan the pinball table design and had a bunch of art ready to implement.

final

We added a bunch of polygons and tried the game, but when we started to see the frame rate drop, I knew what I needed to do.

See you in the next adventure, Part 04: The spatial partitioning.

Comments

Other Posts

Archive

You can subscribe via RSS or follow us @amanogames_

Making a pinball game for Playdate: Part 07, the debugger

Making a pinball game for Playdate: Part 07, the debugger

Searching for a debugger on Linux

Making a pinball game for Playdate: Part 06, the profiler

Making a pinball game for Playdate: Part 06, the profiler

Learning how to use a profiler

Making a pinball game for Playdate: Part 05, the spatial partition

Making a pinball game for Playdate: Part 05, the spatial partition

2 Bits image formats.

Making a pinball game for Playdate: Part 03, the first level editor

Making a pinball game for Playdate: Part 03, the first level editor

How did we choose our first level editor for the game?

Making a pinball game for Playdate: Part 02, the physics

Making a pinball game for Playdate: Part 02, the physics

Let's talk about physics.

Making a pinball game for Playdate: Part 01, the language

Making a pinball game for Playdate: Part 01, the language

Welcome to this December adventure, where I will try to write about the process of our last game, Devils on the Moon pinball. Today I will talk about our choice of programming language for the game.

Let’s finish this

Let’s finish this

We are back working on Pullfrog! What happened?

Let's talk about Don Salmon

Let's talk about Don Salmon

Don salmon, a new platforming game made in Godot and a small update on Pullfrog

Spooky eyes and level editors

Spooky eyes and level editors

Last year we made the decision to take a break and focus on a spooky game around the spooky season.

This kills the frog

This kills the frog

After rewriting the physics system for the third time, it was time to start working on more fun stuff. The frog death system™.

On starting a game

On starting a game

A couple of things I would recommend when starting your first game on the Playdate.

How to correct a corner

How to correct a corner

There are many techniques that you can apply so that a platformer game feels good. One of those is corner correction.

On "Bouncy" Animation

On "Bouncy" Animation

Another Equally important decision, is choosing which poses you want to emphasize in order to get that reactive feeling when a character interacts with the world.

The collision stair case

The collision stair case

As stated on the previous post, updating all the pieces all the time was a bad idea. We needed to figure out a way to update only the ones that needed to be updated after another block got destroyed. The quick and dirty solution was to check all the pieces inside a bounding box on top of the piece that got destroyed.

About Amano & the collision conundrum

About Amano & the collision conundrum

So, a couple of months back, Mario and I were happily working away on The game, finding out the workflow and working out the kinks of developing for the PlayDate. We laid down the main mechanic, blocks were falling and colliding correctly the character was moving alright but we were doing everything on the simulator, NOT testing on the actual device. so when we decided to take it for a spin…  it crashed.

Pullfrog postmortem, Long Live Pullfrog 2-Bits

Pullfrog postmortem, Long Live Pullfrog 2-Bits

So towards the end of the year, Mario managed to get his hands on a Development console for the handheld "Playdate" and we decided to attempt do make a second version of Pullfrog, this time featuring a playful little crank and seemingly less restrictions except for the apparent ones like the black and white color of the screen. Oh the naivety.