Monday, October 19, 2015

A Space Shooter in Curses

Some of you who follow me may know that I have recently built a pretty nifty framework for working with terminals.  ANSI, ASCII, VT100, Windows Console, etc.  Its called Tcell, and located on github.  (Its a Go framework though.)  It offers many of the same features as curses, though it is most definitely not a clone of curses.

Anyway, I decided it should be possible to write a game in this framework, so I wrote one.

I give you Escape From Proxima 5, a 2D multi-axis scrolling space shooter written entirely in Go, designed to operate in your text terminal

The game is fairly primordial, but there is a playable level complete with enemies and hazards.   It's actually reasonably difficult to get past just this first level.

Mostly the idea here is that you can get a sense of what the game engine is capable of, and see Tcell in action.

As part of this, I wrote a pretty complete 2D game engine.  Its got rich sprite management with collision detection, palettes, an events subsystem, scrolling maps, and support for keyboards and mice.  Its also got pretty nice extensibility as assets are defined in YAML files that are converted and compiled into the program.  (I guess an asset editor needs to be written. :-)

The code is Apache 2 licensed, so feel free to borrow bits for your own projects.  I'd love to hear about it.

Anyway, I thought I'd post this here.  I made two videos.  The longer one, at about 3:30, shows most of the features of the game, animated sprites, some nice explosions, gravity effects, beam field effects, etc.



The second video shows what this looks like on less rich terminals -- say a VT100 with only 7-bit ASCII characters available.  The richer your locale, the nicer it will look.  But it falls down as gracefully as one can expect.


Btw, this framework is now basically design complete, so it should be super easy to product a lot of simples kinds of games -- for example a clone of Missile Command or Space Invaders should be doable in an afternoon.   What makes this game a little bigger is the number if different kinds of objects and object interactions we can have.

Monday, October 5, 2015

Fun with terminals, character sets, Unicode, and Go

As part of my recent work on Tcell, I've recently added some pretty cool functionality for folks who want to have applications that can work reasonably in many different locales.

For example, if your terminal is running in UTF-8, you can access a huge repertoire of glyphs / characters.

But if you're running in a non-UTF-8 terminal, such as an older ISO 8859-1 (Latin1) or KOI8-R (Russian) locale, you might have problems.  Your terminal won't be able to display UTF-8, and your key strokes will probably be reported to the application using some 8-bit variant that is incompatible with UTF-8.  (For ASCII characters, everything will work, but if you want to enter a different character, like Я (Russian for "ya"), you're going to have difficulties.

If you work on the console of your operating system, you probably have somewhere around 220 characters to play with.  You're going to miss some of those glyphs.

Go of course works with UTF-8 natively.  Which is just awesome.

Until you have to work in one of these legacy environments.   And some of the environments are not precisely "legacy".  (GB18030 has the same repertoire as UTF-8, but uses a different encoding scheme and is legally mandatory within China.)

If you use Tcell for your application's user interface, this is now "fixed".

Tcell will attempt to convert to characters that the user's terminal understands on output, provided the user's environment variables are set properly ($LANG, $LC_ALL, $LC_CTYPE, per POSIX).  It will also convert the user's key strokes from your native locale to UTF-8.  This means that YOU, the application developer, can just worry about UTF-8, and skip the rest.  (Unless you want to add new Encodings, which is entirely possible.)

Tcell even goes further.

It will use the alternate character set (ACS) to convert Unicode drawing characters to the characters supported by the terminal, if they exist -- or to reasonable ASCII fallbacks if they don't.  (Just like ncurses!)

It will also cope with both East Asian full-width (or ambiguous width) characters, and even properly handles combining characters.  (If your terminal supports it, these are rendered properly on the terminal.  If it doesn't, Tcell makes a concerted effort to make a best attempt at rendering -- preserving layout and presenting the primary character even if the combining character cannot be rendered.)

The Unicode (and non-Unicode translation) handling capabilities in Tcell far exceed any other terminal handling package I'm aware of.

Here are some interesting screen caps, taken on a Mac using the provided unicode.go test program.

First the UTF-8.  Note the Arabic, the correct spacing of the Chinese glyphs, and the correct rendering of Combining characters.  (Note also that emoji are reported as width one, instead of two, and so take up more space than they should.  This is a font bug on my system -- Unicode says these are Narrow characters.)
Then we run in ISO8859-1 (Latin 1).  Here you can see the accented character available in the Icelandic word, and some terminal specific replacements have been made for the drawing glyphs.  ISO 8859-1 lacks most of the unusual or Asian glyphs, and so those are rendered as "?".  This is done by Tcell -- the terminal never sees the raw Unicode/UTF-8.  That's important, since sending the raw UTF-8 could cause my terminal to do bad things.

Note also that the widths are properly handled, so that even though we cannot display the combining characters, nor the full-width Chinese characters, the widths are correct -- 1 cell is taken for the combining character combinations, and 2 cells are taken by the full width Chinese characters.

Then we show off legacy Russian (KOI8-R):   Here you can see Cyrillic is rendered properly, as well as the basic ASCII and the alternate (ACS) drawing characters (mostly), while the rest are filled with place holder ?'s.

And, for those of you in mainland China, here's GB18030:  Its somewhat amusing that the system font seems to not be able to cope with the combining enclosure here.  Again, this is a font deficiency in the system.


As you can see, we have a lot of rendering options.  Input is filtered and converted too.  Unfortunately, the mouse test program I use to verify this doesn't really show this (since you can't see what I typed), but the Right Thing happens on input too.

Btw, those of you looking for mouse usage in your terminal should be very very happy with Tcell.  As far as I can tell, Tcell offers improved mouse handling on stock XTerm over every other terminal package.  This includes live mouse reporting, click-drag reporting, etc.   Here's what the test program looks like on my system, after I've click-dragged to create a few boxes:



I'm super tempted to put all this together to write an old DOS-style game.  I think Tcell has everything necessary here to be used as the basis for some really cool terminal hacks.

Give it a whirl if you like, and let me know what you think.


Friday, October 2, 2015

Tcell - Terminal functionality for Pure Go apps

Introducing Tcell  - Terminal functionality for Pure Go apps

As part of the work I've done on govisor, I had a desire for rich terminal functionality so that I could build a portable curses-style management application.

This turned out to be both easier and harder than I thought.

Easier, because there was an implementation to start from -- termbox-go, but harder because that version wasn't portable to the OS I cared most about, and fell short in some ways that I felt were important.  (Specifically, reduced functionality for mice, colors, and Unicode.)

This led me to create my own library; I've made some very very different design choices.  These design choices have let me both support more platforms (pretty much all POSIX platforms and Windows are included), increase support for a much richer set of terminals and terminal capabilities, etc.

The work is called "Tcell" (for terminal cells, which is the unit we operate on -- if you don't like the name ... well I'm open to suggestions.  I freely admit that I suck at naming -- and its widely acknowledged that naming is one of the "hard" problems in computer science.)

As part of this work, I've implemented a full Terminfo string parser/expander in Go.  This isn't quite as trivial as you might think, since the parameterized strings actually have a kind of stack based "minilanguage", including conditionals, in them.

Furthermore, I've wound up exploring lots more about mice, and terminals, and the most common emulators.  As a result, I think I have created a framework that can support very rich mouse reporting, key events, colors, and Unicode.  Of course, the functionality will vary somewhat by platform and terminal (your vt52 isn't going to support rich colors, Unicode, or even a mouse, after all.  But Xterm can, as can most modern emulators.)

This work would be a nice basis for portable readline implementations, getpassphrase, etc.  Or a full up curses implementation.  It does support a compatibility mode for termbox, and most termbox applications work with only changing the import line.   I still need to change govisor, and the topsl panels library, to use tcell, but part of that work will be including much more capable mouse reporting, which tcell now facilitates.

Admittedly, if you cannot tolerate cgo in any of your work -- this isn't for you -- yet.  I will probably start adding non-cgo implementations for particular ports such as Linux, Darwin, and FreeBSD.  But for other platforms there will always be cgo as a fallback.  Sadly, unless the standard Go library evolves to add sufficient richness that all of the termios functionality are available natively on all platforms (which is a real possibility), cgo will remain necessary.  (Note that Windows platform support does not use CGO.)