Armor Alley: Web Prototype

TL;DR version: I played this in the early 1990s on an old 8088-based IBM-PC compatible; this is my interpretation of it. Play now at /armor-alley. Related: Development process, screenshots etc. Also on GitHub.

A browser-based interpretation of the classic 1990 game.

Armor Alley is a side-scrolling simulation involving strategy. The primary goal is to get a van across the battlefield to the enemy base. Of course, it is not that simple; the van is completely unarmed, and incredibly vulnerable. You must defend the van with a convoy of tanks, missile launchers and other units on the ground, in addition to providing air cover with your helicopter against identical enemy forces.

The Armor Alley Web Prototype home screen. Play it now or read more about the original game, units and strategy on Wikipedia.

A quick fly through of the AA Web Prototype in tutorial mode. Basic mechanics, defensive and offensive tactics are explained.

Why do this?

... Because.

Any application that can be written in JavaScript, will eventually be written in JavaScript. -- Atwood's Law (2007)

Writing a browser-based game using HTML, CSS and JavaScript is a great way to learn, re-learn and experiment with approaches to client-side programming. Games require a depth of logical thought, planning and effort to build, and encourage experimentation in architecture and development style.

Performance and scalability are both important factors in building games, and both present learning opportunities in regards to writing performant code that is compatible with a number of platforms and devices. Regardless of fidelity, a working game prototype can be both educational and fun.

The reference: Armor Alley, PC-DOS version (1990)

Premise

Build and defend convoys of Tanks, Missile Launchers, Infantry, Vans and Engineers as they cross the battlefield, using your helicopter for both offense and defense. The goal is to get your van to the enemy base on the other side of the battlefield.

Memory, DOM node count and JS/DOM garbage collection

Memory and DOM node count rising and falling over time, with ideal case of DOM nodes (green line) being properly GCed as JS objects and DOM nodes they reference are cleaned up.

Normal gameplay and memory allocation is illustrated above in blue, along with a growing number of DOM Node references (green.) In this case, the helicopter's machine gun fires 64 rounds and nodes are added in linear fashion. When the gunfire objects are destroyed, things settle down and eventually a garbage collection event happens.

When JS/DOM nodes are dereferenced via JS object destruction / clean-up, the remaining DOM nodes can be properly garbage collected. A natural GC event reflects this at the mid-point, followed by the remainder of the new nodes with a manual GC event invoked toward the end.

Chrome DevTools' "Detached Dom Trees" under the Heap Snapshot Profile section can also come in handy for finding leaked DOM nodes; the detached DOM is included under the Containment View.

At time of writing (Nov 1, 2013) there might be a bug related to GPU-accelerated DOM nodes not being GCed, or simply not being reflected in the Chrome DevTools graphs. See #304689 for details.

"AI"

Actually, quite dumb. "Rule-based logic" is a more appropriate description of this implementation.

Sound effects

Sound greatly enhances the game experience.

Original 8-bit sounds could not be re-licensed; modern replacements (and new sounds) were mixed in from numerous Creative Commons and free sources on freesound.org. The hi-fi sounds made it more fun to blow up things, in particular.

Distance affects volume, and ideally, panning effects on sounds (off-screen sounds are more quiet, and so on.)

Miscellaneous efficiency & performance notes

Collision detection is largely just math. Caching / invalidation would probably be more expensive, not worth the effort.

Batch DOM changes, particularly queueing and removal of nodes as the result of object destructors (i.e., a bunch of GunFire object instances dying.)

In retrospect: things I would change or revisit

Revisit object, data & function inheritance - could most all game objects inherit from a "sprite" base of some sort?

Smarter collision detection algorithms could be researched and implemented.

Event broadcasting? Would this be smart to use in terms of abstraction? (Still not sold.)

Different "exports" / API per-object? More abstraction, less assumption about css, data, dom?

Better "sprite" abstraction per-object. Easier DOM manipulation?

Sprites in CSS earlier on / SASS / compass for automatic optimization

Avoid writing anysetInterval() / setTimeout() calls. Currently used for post-explosion delays before object destruction (DOM node removal, object clean-up.) Smarter: Use existing animation loop to apply an action after a given number of frames, and destroy object that way. This has been partially implemented.

TODO: tweaks and other bits to tidy up

Remove setTimeout() calls used for destruction of objects, move toward using animate() + frameCount for timing instead (some of this is implemented - see FrameTimeout() in code for reference.)

Re-review object creation, memory allocation and garbage collection. Currently not too bad, but always room for improvement. Object pooling could be used for common objects like gunfire, etc.

Further optimization considerations: Image sprites and sound sprites, where applicable. Remove animated .GIFs in favour of sprites + CSS animations, if it is faster / smoother.

Features not in the original game

Enemy helicopter can hide in clouds, and can bomb passing tanks ("Stealth cloud bombing mode".) Alternately, player can pass over enemy anti-aircraft guns, missile launchers and the enemy base, as well as the enemy helicopter, undetected. Adds a fun element to the game. Sneaky.

A brief history of rounded corner CSS 2 hacks and some examples of effects using border-radius, box-shadow and other fancy CSS 3 attributes (and vendor-specific extensions) allowing modern browsers to render shiny UI designs entirely from code.

Security, load time and user experience are all affected by the amount of inline Javascript blocks and third-party script "includes" being crammed into some modern sites, particularly commercial and tech blogs. This entry is a rant, and some suggestions to improve performance.

A hacker type can't simply plant basil and cilantro outside, and leave them alone to grow; of course there has to be something else, preferably nerdy, in the process. This is how I ended up getting into time-lapse photography and making videos from sequences of photos using a Canon camera, the free CHDK software, and QuickTime.

When JS goes bad: Remote iFrame tricks on legitimate (or phishing) sites can load Javascript exploits or "shellcode", which can mean drive-by downloads and other risks. This is an example of some heavily-obfuscated code seen on a recent Facebook phishing site.

The final, and overdue, part in a series on Javascript animation techniques: Creating tweens, simultaneous animations and event handling are discussed. A simple animation API, demo and source code is included.

Javascript performance learnings: Memory leaks and management, event delegation, performance tweaks, debugging, UI observations and side thoughts from a web development perspective from my time working on the Ajax-heavy redesign of Yahoo! Photos, between 2005 and 2006.

The final, and overdue, part in a series on Javascript animation techniques: Creating tweens, simultaneous animations and event handling are discussed. A simple animation API, demo and source code is included.