Implementation notes Glorious dot graphics. ---------------------------------------------------------------------- 0. Concept I spent the past few months playing Final Fantasy VI, which is a great game in every respect, and it's also the last Final Fantasy before the series moved into the 3D world. I found those 2D dot graphics absolutely charming and thought I had to share them. Since this will be just low resolution dot graphics, I figured I will just draw them in the terminal. How hard can it be? ---------------------------------------------------------------------- 1. Dot graphics Drawing a single sprite wouldn't be so fun, I figured I will do an animated sprite, in color. I picked Tina's walking pose for this purpose, which includes 9 unique sprites: 3 sprites for each of the up/down/left directions, and the right direction sprites are obtained by mirroring the left. I added a 10th sprite (low HP pose) for when the program terminates, because why not. There are two technical details with this plan, the first is in encoding and rendering of these sprites. I thought the latter would be a trivial application of ANSI control codes, except it turns out approximating Tina using only 16 colors looks quite awful. I can get slightly more shades if I use Unicode characters U+2591 through U+2593, but not every terminal supports Unicode. What most terminals (except Windows console) do support is ANSI with a 256 color predefined palette, so that's what I went with. For encoding the sprites, I developed a custom variant of LZW. I could have just gone with gzip+base64, but doing it this manually means I actually have control over every byte in the final source. This includes making all characters printable and excluding forward slash characters, which turns out to be handy later. ---------------------------------------------------------------------- 2. Interactive graphics The other implementation detail has to do with reading input. I could have just let the program execute some kind of time-based loop, but it would be great to get some keyboard interaction. Normal console input involves some press-enter-prompt so I would like to avoid that. So I sampled the list of usual programming languages installed on my local machine, and turns out, Ruby is the only one that included a library for reading raw console input one character at a time (via "io/console"). I would need to install something extra for every other language, so Ruby it is. It also seemed oddly appropriate to use a language named "Ruby" for something related to Final Fantasy. But even with the convenient console library, Ruby doesn't seem to let me do non-blocking IO. Fortunately, it's easy enough to spawn threads in Ruby, so I end up with a dedicated (blocking) IO thread that writes to a global variable. There is probably some thread safety issues with that, but none that I care about. ---------------------------------------------------------------------- 4. Testing Tina has been verified to work in these environments: - ruby 1.9.3p484 on Linux (putty) - ruby 2.1.5p273 on Linux (xfce4-terminal) - ruby 2.3.6p384 on Linux (xterm and gnome-terminal) - ruby 2.3.6p384 on Cygwin (mintty) For some environments such as "screen" or "tmux", you might need to set the TERM environment variable to "xterm-256color" to make use of the 8bit color palette. ---------------------------------------------------------------------- 5. Finally... The colors are slightly off and the IO thread felt like a hack, but by the end of it, I got some nice dot graphics that I can view from a distance, so I was really happy about it. Really, the most difficult part about this program was simply finding the time to write it. What have I been doing for the past few months? Wait, don't tell me...