How to make a Game Boy SHMUP with GB Studio without losing your mind

Creating a shoot ’em up for Game Boy in GB Studio is pure (bullet) hell. The console’s technical limitations make it a nightmare, but it’s exactly within those constraints that the fun begins, as we try to figure out how to get it to work. Also GB Studio has its own internal rules that we must follow if we don’t want our beloved handheld to file a complaint for mistreatment. As a result, the process becomes a kind of puzzle where we need to keep a good number of variables in mind.

With all these questions swirling around, I tried to build a functional prototype that includes everything I  love about the genre: side-scrolling gameplay, no scene transitions, plenty of enemies, environmental interactions and no slowdown or flickering. The only rule I set was to use GB Studio exclusively, without any hardcoded modifications, as a challenge to see if I could do it without deep programming knowledge. The result was this:

It exceeded my expectations, even if some of my solutions were a bit unorthodox and arduous. Because of that, I thought it’d be worth sharing my experience tackling the five main problems I faced during the process.

The default SHMUP scene

Alright, let’s start with the obvious one. The default scene included in GB Studio for making shoot ’em ups is too limited, mainly because the player actor can only move in one direction (either X or Y), which seriously restricts gameplay possibilities.

Luckily, Shin’s SHMUP Reloaded plugin helps bypass that limitation by adding four-directional autoscroll, smooth multidirectional movement and player collision box customization. It also changes trigger behavior: instead of activating when the player collides with them, they activate automatically as soon as they appear on screen. This last feature turns out to be crucial for solving some issues.

The level size

As the GB Studio documentation states, there are background size limitations for a scene:

  • Both the width and height of a background must be ≤ 2040 px  
  • The width × height must be ≤ 1,048,320 px

This means that, if we want to create a horizontal shooter with no vertical scrolling, our background should be no more than 2040×144 px, which is 255×18 tiles. If you look at the video above, that corresponds to more than a minute of uninterrupted gameplay, assuming we set the scroll speed to 8 in the settings menu. For comparison, the first section of stage 1-1 in Gradius/Nemesis lasts around two minutes, so in our case, that’s already enough for a full, seamless experience.

Still, we can go one step further if we want even longer levels. Thanks to the new common tilesets feature in GB Studio 4.0, we can perform instant scene transitions as long as both share the same tileset. The critical element is to ensuring the end of one scene and the start of the next are perfectly aligned, and moving the player to the same coordinates during the transition. In my case, I didn’t find it necessary, but the option is available if you want it.

The enemy count problem

Now things get tricky. We have a huge stage, but we also have to deal with limitations regarding the number of actors that can appear simultaneously on screen and in a scene at once. Let’s recap:

  • 10 maximum sprite tiles in one row (scanline) before dropping out  
  • 20 maximum active actors on screen
  • 40 maximum 8×16 sprite tiles on screen
  • 20 maximum actors per scene

With only 20 enemies available, the level will feel empty! The only effective solution is to repeatedly reuse sprites. Since enemies only stay on screen for a limited time, we can reactivate and reposition them once they leave the visible area. This is where the SHMUP Reloaded plugin’s trigger system becomes extremely helpful. By calculating the exact moment when a defeated or off-screen enemy can be reused, we can set a trigger to reposition and reactivate it at the right location.

The easiest way to manage this is by dividing your 20 available actors into groups by enemy type. In my case, I used this setup:

  • 12 enemies (9 enemy types)
  • 1 item spawner
  • 4 collision triggers (more on these later!)

Depending on how you organize your enemy waves, you’ll need a slightly different setup. At my level, green enemies appear in groups of four. Right after they leave the left edge of the screen, I include a trigger that repositions them and reactivates their behavior if they’ve been destroyed. This way, I avoid using on update off-screen events, which saves precious CPU time. And in GB Studio, resource management is everything.

Regarding the number of enemies appearing simultaneously on screen, we can try replacing some with background tiles as an alternative. If enemies remain stationary and don’t move, they could be turned into animated background elements, with an invisible actor detecting when a weapon strikes them.

Collision

This one’s optional, but I consider it essential. By default, Shin’s plugin only detects collisions on the axis opposite to the scroll direction. That means if your game scrolls horizontally, your player will only collide vertically with background solids. In other words, your ship can happily fly straight through horizontal walls. Cool for “open sky” games, but I’ve always loved those claustrophobic cave sections where you have to dodge the terrain itself.

In the list of actors above, I reserved four as collision triggers. These are invisible 24×8 px actors placed along the vertical walls of the stage so that our ship collides with them when the On Hit event is triggered. To make this work properly, you’ll need to slightly adjust the collision bounding box of each wall actor. In my tests, I found that the ship failed to detect collisions correctly when invisible walls overlapped solid background tiles. The fix? Move the collision box 3 px before the actual wall. That way, the ship explodes exactly when it should. Just like with enemies, I reuse and reposition these four invisible actors as the stage scrolls forward. Because of that, your level design needs to be carefully planned to never exceed those limits.

Bullet hell

A good SHMUP isn’t complete without plenty of bullets flying around for the player to dodge. Unfortunately, GB Studio also has limits here: by default, both the number of projectile definitions per scene and the number of simultaneous projectiles on screen is capped at 5. That might be fine for some designs, but it’s easy to hit that limit fast.

There’s a small workaround that lets you increase the number of bullets on screen by reducing the number of unique projectile definitions. Shin’s tutorial explains which variables make a projectile unique, so we know that changing its direction, target or source won’t make it unique.

To tweak this, open your project’s engine files and look for projectiles.h under game > advanced > eject engine > include folder. There you’ll find:

#define MAX_PROJECTILES 5
#define MAX_PROJECTILE_DEFS 5

Recent GB Studio versions are limited to five definitions, but if lowered, you can increase the other so the total still reaches ten. You can also change projectile definitions at runtime, allowing you to swap weapons mid-game. It’s a bit more complicated, but very useful if your ship uses multiple weapon types. In my case, I didn’t need that since all enemies use the same projectile type with small variations that don’t count as unique, so with a bit of creativity, you can still go beyond the limit.

For more advanced bullet behavior, Fredrik’s Custom Projectile Plugin is an excellent choice. It allows you to use new predefined projectile behaviors, such as boomerangs, gravity bombs, or sine-wave bullets. Best of all, it replaces the projectiles.h file and bypasses the default limit, enabling up to five different projectile definitions with six on-screen at once. This makes it a real win-win, even if performance might slightly decrease. Just be mindful of how these interact with your level design.

Your imagination is the limit (kind of)

There are many other issues to address that have already been covered elsewhere, such as fixed HUDs or screen-filling bosses. In both cases, the solution usually involves some clever overlay tricks, tile swapping, and a few GBVM instructions. In the end, it all comes down to creativity—the same kind of ingenuity Konami and Taito showed back in the early days of the Game Boy. Once again, it’s clear that the platform’s limits aren’t obstacles, but fun challenges for those of us daring enough to enjoy solving them.

Of course, there are more complex solutions out there, but that’s part of the charm of GB Studio: achieving your goals with limited resources and feeling that special satisfaction when it finally works.

Long live shoot ’em ups!

Back To Top