Making "LCD, Please"

Aug 17, 2023

Lcd-Hero

The de-make no one asked for.

Play on itch.io

I love a good set of limitations and on my way to making games with miasma and wind I’ve stopped off at the Game & Watch tier.

LCD. Why.

I played a lot of LCD games when I was a kid. They were mostly terrible. Before the Gameboy existed, mostly terrible in your pocket was great and we loved it.

Gunpei Yokoi invented the Game & Watch LCD game in ~1980 at Nintendo, apparently after watching some bored guy mess around with a pocket calculator. Legends, the both of em.

The first LCD games were very basic reconfigurations of digital watch tech: shift registers and low-segment-count displays. As time progressed things got more complex, and not really for the better. You could be satisfied with a ball juggling LCD game but going too far was asking for disappointment.

Lcd-HistoryNintendo

Nintendo's first, best-selling, and last LCD games

Nintendo had a good number of innovations in game, control, and case design over the years. When the Gameboy was released in 1989 (also from Yokoi, damn) they mercifully shuttered their Game & Watch corps. Lucky for us, other companies stuck around in the LCD dungeon for a few more years.

Lcd-HistoryOther

Not shown: thousands of other makers and games

Most LCD games produced in the 80’s and 90’s were shameless clones of Nintendo’s originals. A few companies like Tiger with their licensed shovelware, Bandai with their layered-screen titles, or Epoch with their creativity, were stretching the format a little bit beyond Nintendo. Great job fellas.

Lcd-HistoryMine

Old LCD games salvaged from the attic.

The two LCD games I still have from my youth are Plane & Tank, a Radio Shack badged clone of Nintendo’s Helmet, and Rambo, an Akklaim shooter that combines a few classic mechanics. I fired them both up while writing this devlog and honestly they’re still kinda hard to put down.

Lcd-HistoryBest

'Lost in Space' & 'Bombsweeper'

“Zero depth” is a good way to describe most LCD games of yore. I spent some time looking for a counterpoint and from that lot, Lost in Space (1989) and Bombsweeper (1987) stood out as two of the best. Lost in Space is a fully realized monster hunting 3D maze game from Epoch and Bombsweeper is a wall-pushing puzzler from Nintendo. Both are deeper and more satisfying than what you’d expect. I didn’t know about either of these games back in the day.

Let’s Go

Bringing it back. This post is about the LCD de-make of Papers, Please.

I’ve already mined the 1-bit Mac era so there should be no surprise that I’m now back with my shovel, digging up liquid crystals. Looking at 1980 LCD game tech with 2023 eyes, there’s a few cool things:

  1. No pixels. These are proper little drawings that you can turn on and off.
  2. No overlapping graphics. A totally unreasonable limitation. Love it.
  3. No touching graphics. Really twisting the knife.
  4. Crushing framerate. Just a few fps.
  5. No advanced logic. Shift registers only. Ignore this one. Maybe next time.

All these limits are good fun for modern indie developers but it was mostly #1 that got me interested in the format. Some of those games had really charming segment and background art.

I figured the low-action elements of Papers, Please could fit snugly with #4, and making randomly-generated faces with the idiosyncratic display tech seemed like the perfect thing to burden myself with.

No one (*) cares about LCD games in 2023 though so let’s just call this project a fun diversion. I started working on it a few years ago on a lark, convinced my wife Keiko to help me, spent a few days on it here and there, and finally crunched to finish it up for the tenth anniversary of Papers, Please.

(*) Except me & you.

Have Limited Display, Need Randomized Faces

To make a procedural face generator with this antique display tech, the first step was to forget everything I was doing in the original game.

OldFaces

Original game. Individually-drawn faces with marked parts, jumbled to make new faces.

Nothing about this method works on a segmented LCD, and the somber style isn’t a good fit for the Game & Watch look anyways. This de-make called for something lighter and more cartoony. With that in mind, I drew a bunch of ideas and just slowly adjusted things over time. Eventually it was both good enough and also too spider-webbed to change any more.

Lcd-FaceDraw2

Drawing progress

Lcd-FaceAllSegments

Final LCD segment art

Lcd-FaceGallery

Some resultant faces

The two main tricks I used for variety were to divide standard features into multiple parts, and to design pieces that could be used in multiple ways.

Lcd-FacePartials

Using partial segments from an fully-defined eye.

Lcd-FaceShared

Reusing the same LCD segment for different features.

The whole thing was one big interlocking set of puzzle pieces. Adjust one piece and the effect cascades through the whole face. Fortunately, in the end it’s still just a static image. What you see is what you get. No variations, animations, extra dimensions, or even colors. Very refreshing for anyone toiling away on modern games.

Drawing Timelapse

Enjoy in silence.

Tools

Lcd-ToolsProcreate

iPad, Apple Pencil, Procreate

The LCD art was drawn in Procreate on an iPad with the convenience of layers and undo. I really feel for those poor souls 40 years ago working on paper. I am doughy soft when it comes to any kind of asset-creation hardship.

Lcd-ColorChannels

Blocks of green group unconnected segments

From Procreate I brought it into Photoshop and used the color channels for marking segment groups. At this point it’s still just an image so we needed a way to address individual segments/groups for the game’s display logic. Keiko wrote a Python script to split each segment out into subimages and I experimented with a few ways to manually assign names to them. There’s nearly 500 segments in all so this wasn’t exactly self-evident.

Lcd-EdgeTraces

Connecting each segment to the image's edge

First try was to draw thin horizontal or vertical red lines running from each segment to the edge, similar to an actual solder trace. That put all segments in a 1D list around the edge, which could be synchronized with a text list of names. This quickly became too difficult to maintain so on to the second try.

Lcd-BlenderSegments

Named Empty nodes placed on segments in Blender

Next I mapped the texture onto a quad in Blender, created Empty nodes, gave them names, and aligned them over each segment. With a short Python script, these node coordinates are exported to .json, where Keiko’s script combines it with the segment subimages to assign names. Much easier and maintainable once the scripts are done.

I often have random little tool needs this like. “Edit named points on an image”. I usually go pretty far twisting a stock tool to do it, writing something custom as a last resort. Blender’s great in a lot of these cases with how flexible and scriptable it is. Can’t recommend it enough.

Case Design

Along with the fun of designing an LCD panel I also jumped into this project with an itch to work up the plastic case. Back in the day, case design spanned a pretty wide swath from mundane to inspired. Since I’m hitting the nostalgia vein pretty hard I opted to go for something relatively generic, combining the bargain Radio Shack case with a slightly more elegant Bandai Game Digital series case.

Lcd-HardInspiration

I had a few goes at this, first testing out Affinity Designer, a very capable Illustrator-alike.

Lcd-HardAffinity

First (2D) case design made in Affinity Designer

Designer is full of thoughtful features and most importantly feels like modern software that isn’t dragged down by 30 years of legacy. I was fully happy with this case until I decided that actually everything should be in 3D. Over to Blender.

Lcd-HardBlender1

Final (3D) case design made in Blender

Blender’s Eevee viewport renderer is both gorgeous and an immense timesaver. I gave up on Maya after Obra Dinn so maybe things are nicer there now. At the time, this kind of convenience, in Maya, was unthinkable. Thinking it now every day in Blender.

Also a Game

Once the basics of the art were worked out, the course was set and I had to figure out how to port the gameplay. For Papers, Please I decided this meant just the most basic sequence:

  1. Wait for someone to enter the booth.
  2. See their face and read their stated name + country.
  3. Check their passport to verify everything matched.
  4. Stamp APPROVE or DENY.
  5. No story, no other docs, no dialog, no repeat characters, etc.

Focusing on just the stamps would hopefully capture an essential element of the original game and also keep the interface simple. As a personal preference, I enjoy the LCD games with just two left|right gameplay buttons over the more complicated ones with left|right|action or d-pad|action|etc.

An important early choice was that this would be a single-screen game. Having two screens like Nintendo’s Donkey Kong or layered screens like Bandai’s Amazone would’ve opened up a lot of options but please this project is not about options. One screen or go home. I also had a dream of actually getting this hardware manufactured at some point, and price-wise I don’t think anything beyond a simple plastic slab with one screen would be feasible.

As a result, unlike the full game, we don’t have the unimaginable luxury of showing both the entrant’s face and their passport at the same time.

Lcd-FlowRealPass

You can see the face, or the passport, but never both at once

To put some intention behind this no-two-faces-at-once limitation, the core gameplay mechanic is very simply just pure memorization. Memorize what the entrant looks like and what they say, then compare that against the information in the passport. If it matches, approve. If not, deny. The hardware VIEW button was a fairly late addition to (slowly) cycle between the passport and the entrant’s face/statements again for review.

Lcd-FlowDenied

Comparing entrant face and statements to their passport. Sorry Erik.

That’s the easy mode. To add more complexity, there’s also a hard mode with two new rules:

  1. Randomized BANNED and WANTED notices. This is the only vestige of the “daily rules” aspect from the full game. The start of each day may briefly show a banned country, whose residents should be denied, or a wanted person, who should also be denied.

Lcd-FlowRestrictions

BANNED and WANTED restrictions shown at the start of the day

  1. VIP entrants. Same as a regular entrant except the VIEW button doesn’t work. Note their face and statements carefully because there’s no second chance to see them. (This rule’s design, code, art, & script were added two hours before release – Keiko had the idea and it was so good we had no choice but to implement it.)

After working out the basic design, we did our best to keep it sensible with the limited display and low framerate. There was so little elbow room here that I can’t say we floundered around too much. The display for results and in-day progress probably went through the most iterations.

Lcd-GameProgress

Different ways of showing results & progress

  1. Icons to show which parts of the entrant’s info were right/wrong after stamping. Daily progress dots/circles. Dot = stamped incorrectly, circle = stamped correctly. TMI, too confusing.
  2. Simple citation icon if player stamps incorrectly. Progress dots/circles. Better but still has the confusing dots/circles.
  3. Ticker tape showing a star if stamp was correct, blank if incorrect. Conveniently combines result with progress and has a nice 3D effect but it’s even more confusing in practice.
  4. Final. Split progress from results. Show number of entrants remaining on left, collected citations (mistakes) on right.

Programming

A long time ago my wife and I worked together pretty often. She’s a very capable game programmer but ducked out of the industry when we added some kids to the family just before releasing Papers, Please. Since then I’ve been looking for an opportunity to drag her back in and this was the perfect project. She handled nearly all of the programming here.

The game is written in an old favorite, haxe, with support scripts in Python. The runtime uses the Heaps library, a lightweight game engine with robust 2D and 3D support. We build to a HashLink target for desktop development and javascript for web deployment.

Structure-wise, our first decision was to create a simple domain-specific scripting language to define program flow for each tick of the clock. This created a nice separation between the display engine and the high-level game-sequence logic.

Lcd-CodeSteps

Logic steps defined in a simple high-level script

For the display control, Keiko wrote a simple in-game editor that enabled me to create named groups of segments, which the Python build script classifies and orders for the runtime.

Lcd-CodeEditor

In-game editor for naming groups of segments

Because the layout of the segments is so wild, each face is generated by selecting groups from the bottom up: first chin, then mouth, nose, and finally eyes.

Lcd-CodeRandom

Stepwise random face generation

A certain chin selection will limit which mouths are available, and so on, up the face. Everything else (hair, ears, shoulders, etc) is independent and can be chosen randomly without worrying about dependencies.

Done

Hopefully this de-make is a bit of quick fun to play. We couldn’t make a career out of these kinds of games but it was a nice distraction. I think there’s still potential in LCD games, and the restrictions are appealing. Recommended, will try again someday.


Comments

Add a comment by replying to this Mastodon post.

Comment display system adapted from here.