Pixel Sharp Graphics at Multiple Screen Resolutions

Pixel art can be very picky when it comes to being scaled as it easily loses its pixel-perfect look, becoming blurry and distorted. This creates an interesting technical challenge for pixel art games since they are drawn at a fixed native resolution, but need to adapt to a wide variety of screen resolutions and aspect ratios.

A comparison of a pixel art character scaled at different sizes with various methods, showing obvious distortion or blurriness when non-integer scale factors are used
Pixel art doesn't like being scaled by non-integer factors. At all.

A Modern Problem

The old gaming consoles – where pixel art was born – would always output video data at only one resolution, regardless of the CRT monitors and TVs they were plugged to. This inevitably led to distorted and blurred graphics, which were made worse by the artefacts generated by the way cathode tubes and video standards worked. At the end of the day, what players saw on the screen looked nothing like the original pixel art and developers could do nothing about it.

A comparison of the original art from the game Zelda and a screenshot from a CRT display, showing how the latter is distorted by the screen
Old screens were super-crappy [source].

Yet today most players expect pixel art to look crisp and sharp regardless of whether they’re using the latest 4K OLED TV or an old 4∶3 LCD screen. In this post we’re going to take a look at how we handled this problem in Guntastic.

Assessing the Situation

During pre-production we investigated which screen resolutions players actually used to get a better idea of the problem scale. While it was quite safe to assume home consoles worked at standard 16∶9 resolutions such as 720p and 1080p (and now 2160p), the situation on PC was far more complex:

Screen Resolution Aspect Ratio Adoption
1920×1080 (FHD) 16∶9 38.21%
1366×768 (WXGA) ∼16∶9 24.76%
1600×900 16∶9 6.05%
1440×900 16∶10 4.59%
1536×864 16∶9 4.48%
1280×1024 (SXGA) 4∶3 4.08%
1680×1050 16∶10 3.62%
1360×768 ∼16∶9 2.89%
Screen resolutions with more than 2% market share in December 2016, according to the Steam Hardware Survey.

By looking at the data above we observed that:

  1. Perhaps unsurprisingly 16∶9 was the more common aspect ratio, with the standard 1920×1080 resolution which was used on more than 38% of PCs (with Steam installed, that’s it).
  2. There are some awkward screen resolutions out there, with queer 16∶9-like aspect ratios, or perfect 16∶9 aspect ratios but uneven sizes.
  3. More than 7% of the users had 16∶10 screens.
  4. Screens with a 4∶3 aspect ratio still existed, although had a shrinking a small market share.

Remember, the data above is from December 2016. Had we started working on the game today, we would have found a radically different scenario: 1080p is used on more than 60% of PCs, while non-HD resolutions (which were predominantly used on laptops) and 4∶3 screens have declined sharply.

A Starting Point

As standard 16∶9 HD resolutions were already the de-facto target to develop for, we decided to use a reference resolution of 640×360 pixels. A canvas of this size scales perfectly using integer factors to all HD resolutions: 2× for 1280×720, 3× for 1920×1080 and so on, including 4K, 8K and possibly more (although I can’t imagine what a pixel art game would look on such screens!). We’ve already seen in a previous post that 640×360 proved to be the most viable option from a gameplay point of view as well.

Our initial implementation of the scaling mechanism was quite standard, and worked by changing the orthographic size of the game camera based on the detected screen resolution. A very good introduction to this technique can be found in the Pixel Perfect 2D post on the Unity blog, which also provides example code that can be easily ported over to UE4.

Thick Borders to the Rescue

To prevent distortions and blurriness at the remaining screen resolutions we identified a simple solution in a slightly modified version of the “Thick Borders” technique outlined in the same blog post.

Basically, the idea is to scale the game to the nearest whole multiple of the reference resolution and then show or hide a small portion of the game world to the sides of the screen to compensate for the small difference in screen resolution. This proved to work well especially on 16∶9-like aspect ratios displays that have resolutions that only differs marginally from standard 16∶9 HD resolutions (e.g. 1366×768, 1360×768, etc.).

A screenshot of the game taken at 1366×768, with the thick border area highlighted
A screenshot of the game taken at 1366×768, with the thick border area highlighted in green.

To support this technique we had to change how the final scaling factor is calculated: if it’s near to the next integer, we round it up, even if we’ll lose a bit of the world to the sides; otherwise we round it down, so thick borders will fill the rest of the screen. The final implementation lives inside our PlayerCameraManager class and takes approximately 80 lines of code. A simplified version is presented below:

// The native resolution of the pixel art
const FVector2D ReferenceResolution(640.0f, 360.0f);

// The pixels per unit (translation factor from pixels to world units, in our case 24px (a tile) = 100cm)
const float ReferencePixelsPerUnit = 0.24f;

void AFolliesPlayerCameraManager::UpdateCameraWidth(FMinimalViewInfo& OutCameraView)
{
    if (GEngine == nullptr)
    {
        return;
    }

    const UGameViewportClient* GameViewport = GEngine->GameViewportForWorld(GetWorld());
    if (GameViewport != nullptr && GameViewport->Viewport != nullptr)
    {
        // Get the viewport size
        const FVector2D ViewportSize(GameViewport->Viewport->GetSizeXY());

        // Calculate the new orthographic width based on pixel art scale and viewport size
        OutCameraView.OrthoWidth = (ViewportSize.X / ReferencePixelsPerUnit) / GetPixelArtScale(ViewportSize);
    }
}

float AFolliesPlayerCameraManager::GetPixelArtScale(const FVector2D& InViewportSize)
{
    // Calculate the new art scale factor
    float BasePixelArtScale = (InViewportSize.X / ReferenceResolution.X);

    // Round it up or down
    BasePixelArtScale = (FMath::Frac(BasePixelArtScale) > 0.9f) ? FMath::CeilToFloat(BasePixelArtScale) : FMath::FloorToFloat(BasePixelArtScale);

    // In the extremely rare case where the display resolution is lower than the reference resolution we
    // also need to protect against divisions by zero, although in this case the game will be unplayable :)
    BasePixelArtScale = FMath::Max(1.0f, BasePixelArtScale);

    return BasePixelArtScale;
}

While thick borders won’t work well for some games since they would inevitably affect gameplay by changing the portion of the world that is visible to the player, they worked quite well for us. In Guntastic every level need to be completely self-contained to fit on a single screen, and having additional room to spare to the sides even gave us a chance to fill these areas with additional details. As an additional precaution, we also established a safe area of one tile around every level that can be hidden, without affecting gameplay, in the very rare cases where the scaling factor is rounded up instead of down.

Handling Out of Gauge Screens: Letterboxing

Although thick borders did the trick in most cases, they failed to handle situations where the area to cover to the sides was way too big, in example with some 4∶3 screens and uneven resolutions such as 1600×900. Since these screens were not widespread we decided to solve the problem by applying a simple letterboxing effect. This also served as a failsafe solution in case a player is using a very strange resolution we didn’t directly account for.

A screenshot of the game taken at 1600×900, with the letterboxing effect visible to the sides
The game on a 1600×900 screen, with the letterboxing effect visible to the sides.

We initially tried to apply the letterboxing effect through the built-in vignette post processing filter, but it proved difficult to control and integrated badly with the pixelated look of the rest of the game. Currently, the effect is implemented inside the game world by using a simple rectangular static mesh, with a big central hole that helps keeping overdraw to a minimum. Not the cleanest approach, but it gets the job done!

The Final Result

In the end, every level in Guntastic is composed of 34×24 tiles. The playable area only account for 24×16 of them (which is approximately our native resolution of 640×360 pixels), with the rest being there only to support the thick borders and letterboxing techniques. The following table and figure show which scaling factor and techniques are applied at common resolutions:

Screen Resolution Scaling Factor Visible Techniques
1920×1080 (FHD) 3 None
1366×768 (WXGA) 2.1 ⇒ 2 Thick Borders
1600×900 2.5 ⇒ 2 Thick Borders, Letterboxing
1440×900 2.3 ⇒ 2 Thick Borders, Letterboxing
1536×864 2.4 ⇒ 2 Thick Borders, Letterboxing
1280×1024 (SXGA) 2 Thick Borders, Letterboxing
1680×1050 2.6 ⇒ 2 Thick Borders, Letterboxing
1360×768 2.1 ⇒ 2 Thick Borders
Scaling factors and techniques applied to screen resolutions with more than 2% market share (December 2016, Steam Hardware Survey data).
A figure illustrating the scaling factor applied at different resolutions
  • Green: 1× scaling factor.
  • Blue: 2× scaling factor.
  • Yellow: 3× scaling factor.

Conclusion

In this post we presented the solution we adopted to support multiple screen resolutions in Guntastic, which is a mix of three different techniques: scaling, thick borders and letterboxing. While definitely not perfect, this approach was quite simple to implement while remaining – we hope – future proof and flexible enough to handle even niche resolutions.

The Basics of Guntastic

In a previous post we went over some of the design decisions that need to be tackled when first starting out a pixel art platformer. In particular, we went over the importance of defining a reference grid, and what are the gameplay implications of choosing a certain native resolution. In this post we’re going to take a look at how we approached these decisions in our upcoming game, Guntastic.

What’s Guntastic About Anyway?

While brainstorming the game we knew we wanted to create an over-the-top, one-shot one-kill multiplayer shooter that could be played on a single screen, shared between all the players to support ruthless living room competitions.

A Guntastic level inside the game editor
Every level tries to pack a lot of different gameplay possibilities in a very small space [view fullscreen].

We wanted the game to feature levels loaded with weapons and powerups, as well as dynamic elements (such as jump-pads, lifts, traps and so on) that created spectacular ways to frag opponents. We also wanted it to be simple enough for newcomers to immediately get some fun out-of-it, yet elaborate enough to entertain seasoned players.

Gameplay First

That doesn’t sound like a complex idea, does it? Still, it’s already enough to set multiple requirements that need to be carefully taken into consideration:

  1. Since the game revolves around multiplayer shoot-outs, players need to always be aware of what’s going around them: where adversaries are, which weapons are available, etc. This means the whole level should be visible, all the time.
  2. Yet, everything should fit on a single screen, where there should be enough room for four players that need to move, shoot, jump and so on.
  3. Levels should also be somewhat elaborate in order to accommodate multiple pickups, dynamic elements and fancy gameplay. Big, empty, boring rooms are out of question.
  4. Visual clarity should be king: the game should feel clear and predictable. This is not only important to make it more approachable for new players, but it’s also required in order to support advanced gameplay dynamics for expert players.

Choosing a Native Resolution

As we’ve seen in a previous post, the size of the playable area in a pixel art game is limited by its native resolution. Since we needed as much room as we could afford for our levels, we immediately went for a 16∶9 aspect ratio: this gave us some extra pixels to work with, and is also what players seem to expect nowadays anyway.

Modern pixel art games that use a 16∶9 aspect ratio tend to be drawn on a 640×360 canvas, so we went with that too. We’ll talk about why this is considered to be one of the best native resolutions in a future post, so for the moment just trust me on this one.

Defining The Grid

Finding out the correct tile size required some more time and experimentation. Beyond gameplay considerations, we also needed to deal with the fact that none-of-us had any previous experience with pixel art whatsoever, and none-of-us could afford to work on art full-time. Being only two people means you’re forced to wear a lot of different hats to make things work.

16×16: Too Small

A mockup of a level using a 16x16 grid
Definitely not the droids tiles we're looking for. But please enjoy our first character ever, a robot zombie.
  • Visible area: 40×22.5 tiles.
  • Pros: a lot of horizontal and vertical space. Low-res graphics is easier to draw. Allows for characters that are taller than wider (the default in most games).
  • Cons: everything is so small that it’s difficult to know what’s what, seriously impacting visual clarity. Graphics is too low-res for what we had in mind.

32×32: Too Large

A mockup of a level using a 32x32 grid
Not these, either.
  • Visible area: 20×11.5 tiles.
  • Pros: higher resolution graphics.
  • Cons: too few tiles create insufficient horizontal and vertical space. Art resolution is too high.

24×24: We Have a Winner!

The first mockup of a Guntastic level
Now this might work!
  • Visible area: 26.666…×15 tiles.
  • Pros: medium-res graphics, solidly within our grasp. Enough horizontal and vertical space for slightly complex levels provided that…
  • Cons: …we keep characters a tile wide and height, not more. This means to enforce additional constraints on the design of the characters.

While not so common as people tend to prefer power-of-two grids, this was a tradeoff that worked well for us. It was simple enough to draw, yet allowed for additional details over 16×16 tiles, but more importantly gave us some more space to work with over a 32×32 grid. 24×24 tiles also proved to work well when dealing with multiple screen resolutions as they allowed for a safe zone at the margins of the screen. We’re going to talk about this in detail in a future post.

A Guntastic level inside the game editor
Although we've taken steps to make it less apparent, everything is tightly aligned to our 24×24 reference grid [view fullscreen].

The Bottom Line

There’s no right native resolution and grid size when it comes to pixel art games: experimentation around gameplay and art constraints is the only way to find out what works best.

Baby Steps in Pixel Art

Guntastic is our first indie game, our first platformer and our first pixel art game: a lot of firsts! When we started production on the game we had therefore a lot of things to figure out.

This post wants to be a short introduction to some of the principles at the core of a pixel art platformer. An upcoming post is instead going to focus on how we tried to apply these principles to our game.

Grids Are Awesome

Let’s begin by talking about grids. A grid is a simple structure that can be used to organize some kind of data, and comes-in handy in multiple disciplines including design, programming and art. Thanks to their flexibility, grids have been used in games since forever.

From a design perspective, having a fixed reference grid helps to enforce the concept of modularity throughout the game. This improves the player perception of the world by providing easily identifiable patterns and a sense of scale, which help him navigate the world and take decisions in an intuitive way. In a well-designed platformer, a player won’t ever need to think about whether he can make the jump to next platform or fit in a passage, he will just know it at a subconscious level.

A screenshot of Bomberman (NES)
The entire gameplay in Bomberman is built on the concept of grid.

Grids are also dead-simple to work with during development: a grid tile is the basic unit that’s used to partition the game world, and everything is sized according to that, starting with the characters.

For example, if a character takes up 1×2 grid tiles, the platforms in the game will need to be at least one tile wide, passages two tiles tall, an so on. From there, we’re able to define how fast the character can move, how high he can jump (and coincidentally how far two platforms can be) and so forth, all based on the size of a tile.

While grids are used in all kind of games, platformers tend to exploit them more than other genres because their gameplay largely depends on the player ability to perform complex series of movements. These are only possible in a meticulously organized game world. Of course this is only half of the problem, the other half being the game controls, which are going to be the topic of a future post.

Grids and Art: Choosing a Pixel Density

Grids also work well for art, as they provide artists with a system that makes creating reusable, modular assets easy. This is especially true for pixel art since pixels already happen to be naturally laid-out on a grid.

A screenshot of Castlevania 3 (NES)
Pixel art games, like Castlevania 3 above, have been using grids to organize art since forever.

How many pixels compose a single tile of the grid define the pixel density (or resolution) of the pixel art itself. The more pixels we put into a single tile, the more dense our tiles will be and the more high-res the final art will look.

Tile Size Available Pixels
8×8 64 pixels
16×16 256 pixels
24×24 576 pixels
32×32 1024 pixels
How many pixels are available in a single tile at some common tile sizes.

It’s important to keep in mind that the amount of pixels to deal with scales quadratically with the size of a tile – and so do the time and skill needed to produce and polish the art. Tiles of 16×16 or 24×24 pixels are usually enough for most games as they allow for both fast iteration times and interesting visuals, while anything over 32×32 pixels steers more and more away from a pixelated look.

Several articles have been written on what defines pixel art and what is the threshold where pixel art stops being pixel and becomes something else – as well as about the effect different approaches have on the final public. Here’s the ones we found most interesting:

Okay, But How Many Tiles On One Screen?

Choosing how many pixels make up a grid tile, however, not only depends on artistic taste and skill, it’s also a matter of how many tiles need to be visible on the screen for the game to play well.

Pixel art is reminiscent of an era where graphic hardware was fairly limited in the resolution it could work with, and both gameplay and art needed to account for that. For example, the SNES console worked at a base resolution of only 256×224 pixels: for a grid tile of 16×16 pixels this would mean that only 16 tiles could be displayed horizontally at the same time.

A screenshot of Super Mario World
Super Mario World on the SNES was designed to play well at the console 256×224 resolution.

Although modern graphic hardware support crazy high resolutions – 8K displays, for example, support resolutions up to a whopping 7680×4320 pixels – pixel art is still drawn using the same constraints of the past. This helps maintaining the old school look and feeling (which is the whole point of using pixel art, after all), but imposes some limits on gameplay since only a minimal part of the game world can be visible at a time.

Gameplay can change drastically based on the native aspect-ratio and resolution
The original Sonic the Hedgehog game would be far easier to play at a 16∶9 aspect-ratio [source].

To work around this, modern pixel art games tend to use a larger canvas than the classics in order to accommodate more complex gameplay. Native resolutions of either 320×240 or 640×360 pixels, depending on whether they want to stay true to the classic 4∶3 aspect ratio or they want to make full use of modern 16∶9 displays, are the standard nowadays.

A screenshot of TowerFall Ascension A screenshot of The Siege and the Sandfox
Modern games such as TowerFall Ascension and The Siege and the Sandfox not only use very different tile sizes, but also different aspect ratios.

The fact that pixel art is drawn at very low resolutions, but still needs to be outputted on high-resolution displays creates some interesting technical challenges, which we’ll tackle in a future post.

TL;DR

  • Grids are a time-tested, easy to work with way of designing a pixel art game. Defining a reference grid (and sticking to it) not only helps delivering a polished gameplay experience, but also helps organizing and producing art.
  • Pixel density is defined by how many pixels make up a single grid tile. Higher densities requires more work and additional skill to pull out.
  • Both gameplay and graphics are affected by the native resolution of the game. Special care should be taken to make sure the game plays well and looks good at the same time.

Head over to the next post where we take a look at how we approached these issues for Guntastic.