New parallax ANSImation: Millennium Falcon dodging asteroids

I want to push boundaries.

That’s what the original Star Wars films did. Industrial Light & Magic revolutionized special effects with novel new techniques for motion control and amazing model work.

When I work on ANSI projects now, I try to think about ways to do things in ANSI that weren’t possible in the 1990s because of low bandwidth or limited processing power.

How about parallax ANSImation? Well, I cooked up a new one for Blocktronics’ new artpack “Detention Block AA-23”. It features the Millennium Falcon dodging asteroids. Check it out:

Want to know how it came to be? Keep reading.

This is my third parallax ANSI animation. The first was a proof-of-concept with a simple girl sprite in a forest. The second was a collaboration with Whazzit on a mermaid animation; he did the art, I wrote the code.

So what’s new this time? I’m juggling multiple objects in the foreground, and the Falcon itself moves all over the screen rather than remaining fixed in place.

The idea

My initial idea was straightforward, but not easy: Animate the Millennium Falcon bobbing and weaving through an asteroid field just like the moment in “The Empire Strikes Back.” It lasts only three seconds: A side view of the Falcon small on the screen as it slides away; an asteroid flies past; and then the Falcon slides back toward the camera until it fills the screen.

A screen capture of the asteroid field sequence in "The Empire Strikes Back."

A screen capture of the asteroid field sequence in “The Empire Strikes Back.”

I quickly realized that even such a short animation would require dozens or hundreds of hand-drawn frames. With the Falcon changing size and orientation throughout the sequence, it was obviously far beyond my capabilities.

So, I settled on something simpler that I could pull off: A top-down view of the Falcon with no perspective changes. The Falcon would gradually move from left to right across the frame, but would make sudden dodge movements up and down to avoid the asteroids. At the end it would accelerate and fly out of frame.

The look

I would need a Falcon sprite; background layers with diffuse asteroids; and bright, detailed foreground asteroid sprites.

This was ambitious for me. I’m getting better as an ANSI artist, but I have no delusions that I’m anywhere near being on par with the excellent dudes in Blocktronics. I depend a lot on reference images.

For this project, I went looking for pixel art of the Falcon, as well as pixel art of asteroids. There was no shortage of either.

I started with the Falcon. I googled around, and came across this still image on Pinterest:

Absolutely fantastic work, and it even had asteroids, plus the same quote I was intending to incorporate. (There was a twist I didn’t discover until I was preparing to write this blog post — This JPG is a still frame, but the original work by Mazeon was an animation!)

I loved the details on this piece from bitcreator:

Finally, this one was particularly useful because it was almost exactly the same scale as what I needed for my ANSI:

Because it is my intention for these animations to run on my Synchronet BBS and to be compatible with typical terminal programs, I place some constraints on myself: the animation must be 80×24; use the standard 16-color palette; and NOT use the iCE system of mixing “high” colors in both the foreground and background.

Here’s how the Falcon sprite turned out. It has only two states. The second state shows the engines lit up and is used at the end when the Falcon accelerates away.

This two-state sprite has a magenta background which serves as a mask for transparency.

This two-state sprite has a magenta background which serves as a mask for transparency.

A further constraint I place on myself with these parallax animations is that background layers need to look diffused, to help the foreground sprites pop more. I achieve this diffuse look with shaded blocks. Also, because the foreground layers are masked and the background shows through, I avoid using half-blocks on the edges of sprites in the foreground.

When it came time to draw the background asteroids, it took a lot of work to create something satisfactory. The constraints of using only shaded blocks and keeping mostly to shades of high-black (dark gray) made it challenging to come up with believable shapes. Here are the two final layers:

This layer is at the bottom.

This layer is at the bottom.

This layer is above asteroid layer 1.

This layer is above asteroid layer 1.

Finally, I needed to draw some foreground asteroids. These were the most detailed of all the assets I created for this animation, probably because I did them last.

I first made three asteroids: small, medium, and large. With each size increase, I felt like the asteroid looked better.

These are the first three foreground asteroid sprites I drew.

These are the first three foreground asteroid sprites I drew.

After watching and tweaking the animation dozens of times, I realized I needed one more asteroid: A mega-asteroid with tons of detail that was big enough to dwarf the Falcon. So I drew one. Here’s a GIF of that drawing process:

A look at the processing of drawing and adding craters to the mega-asteroid.

A look at the processing of drawing and adding craters to the mega-asteroid.

When the animation was nearly finished, I made a late decision to add a starfield layer. I kept it simple, using a handful of ASCII and ANSI characters including ASCII 07, which looks nice in Pablo. Unfortunately during my first test on the BBS afterward, SyncTerm began beeping annoyingly until the test was finished. I had forgotten ASCII 07 is the BELL control character in terminals. Oops.

The code

So that’s how I achieved the look of the animation. In terms of the code, thankfully I was able to repurpose much of the code I wrote for the mermaid animation. But there were some new things going on.

By far the biggest change was moving the foreground sprites. My previous parallax animations involved a foreground sprite appearing to walk or swim, but fixed to one location of the screen.

My solution was to create JSON files for each sprite with an array of coordinates representing the sprite’s position at a given moment of the animation. I could tweak the sprites’ paths by editing these files. It wasn’t perfect, but it got the job done.

Something else I found was that each sprite frame I opened on screen would slow the animation substantially. So I took pains to keep track of when frames needed to be open or closed. I also optimized the drawing routines by adapting a “repainting” method I cooked up for another project. Basically, I only redraw a character on the screen if it has different colors and/or attributes from the last draw.

I continue to be flustered by inconsistent lag and latency. Sometimes this animation runs really fast and smooth — regardless of whether I’m testing at home or a remote location. Other times, it gets bogged down by latency. I adapted some timer code from my movie player project in an effort to keep the frame rate consistent, but it seems to have no effect when latency is in play.

Conclusion

I’m really happy with how this turned out. I’m proud that this is genuine ANSI text, and that this demo runs on a real BBS. I didn’t export ANSI sprites as PNGs and animate them in Adobe After Effects or something like that.

It’s also been another reminder that good animation is a TON of work. It’s hard to find the time to draw all the assets, all the states, etc, that you need to make something really great.

Did you like it? Let me know what you think!

Share your thoughts!