Friday, March 29, 2024

Building HTML5 Games for the Atari Arcade

Building HTML5 Games for the Atari Arcade

By Lanny McNie, Michael Graves, and Chris Caldwell of gskinner.com

Most HTML5 games are available in isolation so the hardware and browser can be dedicated to gameplay. But that’s not how we envisioned a modern arcade where users could gather, play the games, challenge their friends to high-score dominance, and earn achievements. We had to rethink how we approached game development with a common set of tools.

With Atari Arcade, that game is changing. This site was designed completely in HTML5 for Internet Explorer 10 and Windows 8 touch-enabled devices – although it works great in all modern browsers. In this guide, we’ll quickly get you up and running with your own HTML5 game. The Atari Arcade SDK with CreateJS is one of the first cross-browser HTML5 game development platforms that allow you to take advantage of multi-touch capabilities more easily. The Atari Arcade SDK is just one of many options you should consider. All of the practices we share can be used with other gaming platforms in modern browsers.

In this article, we’ll provide:

  1. Steps to define and build your game
  2. An overview of the SDK’s goals and approaches
  3. Sample code showing integration
  4. Adding flair and/or pizazz
  5. Steps to test, optimize, and deploy your game

Re-imagining a Classic

Invent a concept from scratch. Borrow ideas from other games. At gskinner.com, we were lucky – presented with Atari’s catalog, ranging from simple to complex, tasked with a chance to reinvent them. With visions and mechanics already proven, we were able to piggyback on existing gameplay, and introduce new creative. For launch, we targeted eight of the most popular and recognizable titles.

Visualize

With the computing advancements in the past forty years, we were starting from scratch. We set out to maintain the souls of the originals, which were designed in a more restrictive, low fidelity environment. Here is a snap of the original gameplay in Atari’s 1986 top seller, Yars’ Revenge©.

Classic.

Conceptualize

We started with sketches. Simple, loose, and color-free. They help outline gameplay, general aesthetic, and get our noodles cooking about assets and approaches without focusing on the specific art requirements or details.

Here’s a behind the scenes look at some of our original sketches.

Stylize

Yars’ was both tough and fun to reimagine. Despite being a best-selling title in the late eighties, no one on our team had played it. After playing the original, we felt as lost as before.

  • A Yar is an insect. They fly around.
  • There is a projectile which hunts the Yar.
  • Yars shoot stuff, and can hide in a barrier.
  • The Qotile is the antagonist he aims to destroy.
  • They can transform into a Swirl and shoot at the Yar.
  • But the Yar has a Zorlon Cannon that can be charged up and fired!
  • The Qotile is surrounded by what are those bricks?
  • No, they’re eggs or cosmic cells
  • And the Yar eats them.

We found this awesome comic that shows some vision for design

Finalize

Taking these ideas and discussing our own, we concluded:

  • Yar is mechanical (or in a cool exoskeleton with propulsion instead of wings).
  • He and his weapons are cold, sterile, and metallic.
  • The surrounding environment is natural and serene.
  • The Qotile, its eggs, and spawn are organic and uber-creepy.
  • The eggs hatch into spawn: the projectiles hunting the Yar.
  • The swirl is a projected spawn, which is Yar’s toughest challenge.
  • Consuming the eggs, powers the Yar, which in turn powers the Zorlon Cannon.

Initially we discussed Yar eating the eggs, and sourced a gruesome eating sound. Here is the final, polished visual style.

We considered the story, the scoring mechanic, the levelling system, the animations, the user interactions and the controls for touch for each game. With research, ideation, and aesthetic exploration behind us, we solicit feedback, iterate, and ultimately make decisions.

Strategies for Developing Games

Let’s get into development! Take a short walk through the necessary steps to build on the SDK.

Define a Manifest

We use a very simple, centralized, and standardized means to define and load game assets: a game manifest. A manifest is a simple JSON-formatted outline that describes a game’s key information and its assets. It’s a legend, storing:

  • The game name.
  • A unique ID for the system.
  • A list of JavaScript files the game requires, including the game class, which is instantiated when everything is loaded. We also include a minified alternative for the scripts that is used for deployment.
  • Audio, image, and data (XML, JSON) assets that need to be preloaded.
  • Paths to logos and other artwork displayed in the arcade.
  • Multiplayer information about gameplay modes, number of players, etc.
  • Other optional parameters that help define how the framework interacts with the game, such as whether the game can be continued when the player loses.

It houses the pertinent details necessary to preload and start a game. Here is a look at the manifest for Super Breakout©:

	
{
	"splash":   "arcadeArt/background.jpg",
	"titleArt": "arcadeArt/gameTitle.png",

	"id":       "breakout",
	"name":     "Super Breakout",
	"gameClass": "Breakout.js",

	"modes": [
		{"id":"cavity", "label":"Cavity Mode",
			"src":"arcadeArt/sp-mode-01.jpg"},
		{"id":"progressive", "label":"Progressive Mode",
			"src":"arcadeArt/sp-mode-02.jpg"},
		{"id":"double", "label":"Double Mode",
			"src":"arcadeArt/sp-mode-03.jpg"}
	],

	"dependencies":   [
		"scripts/Ball.js",
		"scripts/Brick.js",
		"scripts/Level.js",
		"scripts/Player.js",
		"scripts/Paddle.js",
		"scripts/LevelManager.js",
		"scripts/LevelSelector.js",
		"scripts/Breakout.js",
		"scripts/ScoreBoard.js"
	],

	"deployDependencies": [
		"scripts/breakout-min.js"
	],

	"assets": [
		{"id":"json","src":"data/data.json"},
		{"id":"bricks","src":"data/bricks.json"},
		{"id":"lives","src":"data/lives.json"},
		"img/lives.png",
		{"id":"paddleData","src":"data/paddle.json"},
		"img/paddle.png",
		{"id:":"brickImage", "src":"img/bricks.png"},
		{"id":"background", "src":"img/background.png"},
		{"id":"scanlines", "src":"img/ui-scanlines.png"},

		{"id":"wall", "src":"sounds/Wall_Hit_02.mp3", "data":2},
		{"id":"brick1", "src":"sounds/Brick_Hit_01_Final.mp3"}
		// Other audio
	]
}
	

Pictured: work you didn’t have to do.

 

Pro tip: Use JSONLint to validate JSON-formatted content.

This approach decouples the game’s assets and the information the game needs about them from the core game logic. Assets get preloaded, modes get populated, Bob’s your uncle.

The Atari Arcade game framework preloads and instantiates each game. A manifest is used to configure and populate the site. When a user chooses your game, everything is preloaded and set up. All the assets are provided to the game in a nice, easy-to-use object hash.

	
// The game manifest includes an image
var assets = [
	{id:"projectile", src:"images/projectile.png"}
];

// Inside the game, we just do this:
function initialize(assets, stage) {
	var bitmap = new createjs.Bitmap(assets.projectile);
	stage.addChild(bitmap);
}
	

The Battleplan

Using the SDK will help you define and implement the methods you’ll need to integrate your game into the Atari Arcade.

Within the Atari Arcade site, games are launched inside an iframe. This creates a sandbox for gameplay and provides easy cleanup when it’s Game Over. Just make a rad game, provide a manifest, and the framework will do the rest. The SDK has a lot of out-of-the-box functionality to get you up and running easily, instead of having to manage peripheral tasks yourself.

The The Quick Start Guide, included in the SDK, provides a more in-depth review of development including an overview all the functionality, utilities, and key framework classes.

The well maintained API Documentation included in SDK, is exported directly from in-line code comments.

Some of the Nitty Gritty

Here is a whirlwind review of some of the key concepts:

Game Initialization and Start

We know the game is preloaded, but the user hasn’t started it. Maybe they’re reviewing the controls, or gazing into the shiny logo. This gives you a chance to initialize your game.

	
// Simply define the function, and it is called by the framework.
function initialize(stage, assets, gameInfo) {
	this.stage = stage;
	// TODO: Add children to stage

	this.assets = assets;
	// TODO: Use to get references to preloaded assets

	this.gameInfo = gameInfo;
	// Use to determine info such as multiplayer, number of players
	// touch enabled, etc.
}
	

Once they click “Start” though, it’s game on.

	
// Simply define this function, and the framework calls it
// when a game is ready to be started
function startGame() {
	// Start!
	this.createBall();
	this.startMusic();
}
	

Tick

A ticker provides a heartbeat to the game, powered by EaselJS’s Ticker. This is where the game updates (and animates) sprites, runs collisions, calculate scores, handles input – whatever floats your boat. The tick is automatically managed for you: stopped and started when necessary, and even throttled down in high-stress situations.

	
// The game framework calls tick at regular intervals while the game is running.
function tick(tickFactor) {
	// Move ball
	this.ball.x += (this.ball.vx * tickFactor);
	this.ball.y += (this.ball.vy * tickFactor);

	// Note: the tickFactor tells you the speed the game is running relative to the
	// defined framerate so you can ensure the game runs at a steady speed.
}
	

Game Quality

One of the biggest disparities across many browsers and devices in HTML5/JavaScript development is performance.

Depending on your hardware, browser, or even the time of day, you may have hardware accelerated performance with Canvas. Sometimes a browser just needs a restart, or a user needs to upgrade their video card. Maybe new drivers are available. Maybe it’s a full moon.

To combat this situation, the Atari Arcade SDK allows you to prioritize features and effects in high or low quality situations. Simply check which quality mode the game is running in, or subscribe to a low quality event, to disable or remove features that don’t perform well under stress. Scale back or remove particle effects, large bitmap animations, or even swap out sprites for lower fidelity ones.

	
// Create a performance monitor
var minFPS = 20;
var threshold = 20; // The number of ticks before toggling low quality
var perf = new GameLibs.PerformanceMonitor(toggleLowQuality, minFPS, threshold);

// Once low quality is toggled, turn off the heavy firework effect.
function toggleLowQuality(lowQuality) {
	if (lowQuality) {
		fireworksEffect.enabled = false;
	}
}

// During a tick, only emit particles if in high quality mode.
function tick() {
	if (perf.lowQualityMode == false) {
		particleEmitter.emit(ball.position, 100, particleProps, defaultParticle);
	}
}
	

In Combat, we turn off projectile trails, tank treads, and other explosion effects when the CPU starts complaining.

Game Score

All games track score differently, but most have similar requirements: numeric points, life count, and levels. A ScoreManager class provides tweened, formatted score – as well as the raw unformatted score for submission. Just point it at your EaselJS Text instance, and add numbers with reckless abandon!

Callbacks

There comes a time when you are finished battling the Quotile scum, and need to let the Yar superiors know how the battle turned out. Did you win? Should we allow you to continue?

Some easy callbacks are available to communicate this (and other significant game scenarios) back to the framework.

	
function onKillPlayer() {
	// Who are we kidding? You lost. Yars is hard!
	this.lives--;
	if (this.lives == 0) {

		// Normally we might do something fancy first.
		// Like fade out the player, or show a death animation
		this.onGameOver();
	}
}
	

That’s it! The framework does the rest – even high score submission and display is handled for you.

User Input

The SDK provides some handy utilities and skinnable components to define and capture user input from the keyboard or mouse. It even translates mouse presses to directional and drag behaviours.

Touch is emerging on the web, and the Atari Arcade games have been designed with touch in mind for Internet Explorer 10. You can use EaselJS and the Atari Arcade SDK to create simple-to-use multi-touch capabilities. It offers a single, cross-browser, and developer-transparent implementation.

	
// Initialization is a great time to set up touch controls
function initialize(stage, assets, gameInfo) {
	// This setting comes from the gameInfo
	if (gameInfo.touchEnabled) {

		// Create a joystick. There are lots of awesome
		// configurations, but this is all you need to get
		// started. Check out the docs for options!
		var joystick = new GameLibs.Joystick(stage);
		joystick.setPosition(25, 25);
		stage.addChild(joystick);
	}
}
	

Other Freebies

A lot of the code and effects used in the Atari-developed games have been wrapped up, documented, and provided as part of the SDK. Have at:

  • Particle effects
  • Game UI controls (non-canvas background)
  • Line and circular collision
  • Handy Math, Point, and String utilities
  • HTML background and parallax effect
  • Sprite utilities

Multiplayer Helpers

You might notice multiplayer classes included in the SDK. Our initial launch includes four multiplayer games that use them, and they are interweaved into the site framework. Third-party developed games currently do not (yet) support multiplayer modes, but we’re in the process of polishing our approach to facilitate immersive, third-party multiplayer experiences in the arcade. Stay tuned!

Juice it Up

Once the manifest is populated and assets are loaded, its time to focus on the flair. Garnish gameplay with sound, particles, killer illustration, and animation. Keep it subtle. Go over the top. Turn your application into a world.

It can be the little things that make an interaction interesting.

In Yars’ Revenge©, The tiny bob and leg animations convince you that he’s flying. The spawn of the Quotile, howling and screeching as they hatch: they’re menacing! The background sounds and splashes help place you in the environment. It’s a private battle, off-site: a lone Yar battling to save his species! Or do they oppress the peaceful Quotile villagers. You decide!

The framework helps out with this too.

1. Logical Motion

Add movements and animation with code. Lots of the included libraries can help: Math utilities, the ScoreManager, TouchBar, and more.

2. Tweens

Include easy animation tricks with TweenJS. Add shakes and kicks and pulses. Transition views, dialogs, or new levels in and out.

3. Sounds

Sound effects, background ambience, and a catchy track transforms the experience immediately. SoundJS makes one of the messiest cross-browser implementations a snap.

	
function fireWeapon() {
	// Play a sound once
	createjs.SoundJS.playSound(this.assets.fireSound);

	// Play a sound, and get a reference to it
	var instance = createjs.SoundJS.playSound(
		this.assets.fireSound,
		createjs.SoundJS.INTERRUPT_ANY,
		offsetMilliseconds, delayMilliseconds,
		loopCount, volume, pan);

	// Call methods, or listen for callbacks
	instance.onComplete = handleFireComplete;
	instance.pause();
}
	

4. Magic

Particle effects are an industry standard for flair. ParticleEmitter adds smoldering effects, sparks, water splashes and smoke trails. It’s highly configurable, and comes with a sweet test harness. It uses an efficient approach by reusing instances combined with bitmap caching.

5. Touch

Users may be touching their browsers with their hands. EaselJS’s multitouch-enabled stage responds back. Skin the built-in controls, or roll out custom touch UI for their fingers.

6. Cheat

Cheat codes are a staple of the game industry, so add your own hacks. The “konami” code is even included the SDK, wire up a callback on the GamePad class, and anyone nostalgic enough to try them can be rewarded with magic. We included support in a few of our games too – see if you can find which ones!

Squeeze it Out

Optimization of HTML5 games is an article on it’s own, but here’s a few tidbits to set you on the right path:

1. Images and Canvas

Canvas does not perform smart area redraw (unlike Flash), and will refresh the entire canvas each tick. Hardware acceleration can assist with this, but generally speaking, try and keep textures smaller. Move static backgrounds out of the canvas. A handy GameUI framework class in the SDK helps with this, and there are other useful classes to do effects outside of the Canvas (such as Parallax).

	
// An asset in the game manifest, which preloads the background
var manifest = [
	{id: "background", src:"images/background.png"}
];

// Backgrounds can be changed in the initialize
// Or alternately somewhere in the game, like a level change.
function initialize(stage, assets, gameInfo) {

	// Note that the background is provided as part of the assets.
	GameLibs.GameUI.changeBackground(assets.background);
}
	

2. Jump on the Video Card

Modern browsers are able to accelerate content, but there are still ways to get the best bang for your buck.

Reuse image instances as often as possible. Cache graphic instances that only need to be drawn once. Use updateCache() in EaselJS to continue adding pixels to cached imagery, such as the tank treads in Combat.

	
// The Arena.js contains the stamp method
function stamp(stamp) {
	// Clear out any old children. They aren't drawn so they
	// only get removed when we want to stamp something new.
	this.groundLayer.removeAllChildren();

	// Stamp the new sprite on top of existing cache
	this.groundLayer.addChild(stamp);

	// Using source-over, it just applies on top
	this.groundLayer.updateCache("source-over");
}
	

Create spritesheets and textures that have dimensions that are a power of two. Zoë now provides this option in the update to version 0.3.0.

3. Use Spritesheets

Using spritesheets in HTML5 allows hardware acceleration to use the same image for all the frames in an animation. There is a single up-front load, the image is cached, and then simply transformed every frame. This also prevents the browser from re-uploading textures to the GPU when an image isn’t being used in a frame.

We use Flash to author some of our animations, but all of the assets are run through Flash for processing with Zoë. We use JSFL to bundle spritesheets together for use with CreateJS.

Another approach for vector art is to export assets directly from Flash using the “Adobe Toolkit for CreateJS”. It can export vector data to be used by the EaselJS SpriteSheetBuilder class to generate spritesheets on the fly at runtime.
Download the Toolkit now.

4. Optimize Your Code

Even though canvas rendering takes up a large chunk of our pipeline, optimizing code is an exercise we encourage.

  1. Find clever ways of reducing load. The ProximityManager game class is an example of this – track sprite proximity of thousands of sprites, with little overhead (based on the original from 2004)
  2. Resuse objects, arrays, and other complex instances instead of making new ones
  3. Pre-define often-used calculations or algorithms.
  4. Use hash lookups instead of constantly iterating an array
  5. Release objects you are finished with to be freed from memory

5. Know the Limitations

Some browsers do better with different technologies. Always plan your game design with a hardware-accelerated browser, but be prepared to gracefully degrade.

  • Stay away from drop shadows and blend modes. Most browsers can’t hardware accelerate these and they’ll cripple your framerates.
  • Watch image sizes on iOS. Anything over 2048×2048 will get automatically sized down by 50%. Similarly, anything created in memory over the limit will not display.
  • Different browsers have different audio channel limits with HTML5 audio, so ensure you stay under 40 total channels of audio (including duplicates for overlapping effects).

6. Reduce Load Times

There’s a ton you can do here.

  1. Tackle your image formats and compression settings head on. Save backgrounds as JPG. Use tools like Omega to blend JPG compression with alpha channels, or ImageAlpha to use indexed PNGs with full alpha transparency. The Atari Arcade games make use of ImageAlpha to reduce the game spritesheets by up to 80%. Squeeze all those pixels!
  2. Compress audio and scrape off what you can. Games don’t need 256kb stereo audio – try to get away with 32-64kb mono (or lower!).
  3. Minify code. Combining them into a single file offers huge savings! We use both server-side and client-side compilers like Google closure to compile JavaScript, and have a dope CSS process with LESS.
  4. Use CDN-hosted libraries. JQuery, Backbone, CreateJS. This is something we have already provided as part of the SDK, but it’s a great tip, so it belongs here.
  5. Use the spritesheet tips above. Besides combined and run-time spritesheets, Zoë provides great frame reuse, with a configurable threshold to reuse similar, or near similar frames. To make things even easier, we recently released a workflow tool to assist with this – check out the Prep for Zoë JSFL Command!

Rinse it Off

Mobile and desktop. Different browsers, different behaviors. The same browser in a different OS, or different CPU, or even a different video card, can have vastly different results. Check in your target browsers, and check often. When testing multiple versions of IE, try using the F12 developer tools.

Do a sanity check when running into bugs by clearing your cache, refreshing your page, or by testing older or newer versions of the same browser. For example, some browsers update often, or transparently, potentially introducing incompatibilities with your code. Sometimes a good ol’ browser restart will help too – especially if something like CSS3D or WebAudio fails completely.

Debugging

To simplify and equalize cross-browser console reporting, we’ve included some utilities that save you headaches and time when logging info to the console.

  1. Atari.trace() – The SDK provides a browser-safe console log method. Console is your friend, and informative errors are invaluable! Its important to get the info you need, without surfacing it to end users.
  2. A “developerMode” flag in the core Atari class allows you to put in testing code and scenarios, without worrying that its making it to your end user. It automatically enables/disables verbose error checking, and when false will supress all Atari.trace() logs.

Local Testing

The nature of HTML5 can make it tricky to test locally. Errors will erupt and there’s browser warnings galore. Cross reference online behavior to see what’s isolated to local testing versus legitimate defects in code. For example, ignore these locally generated cross-origin errors when loading content via XHR.

Some features in HTML5 literally require your game be run off a server. To test locally, use tools like MAMP and XAMPP to run a web server locally.
Mac: http://www.mamp.info/
Windows and Linux:http://www.apachefriends.org/en/xampp.html

Fire them up, point their preferences at your game directory, navigate to your launch page on your local IP, and say good-bye to cross-origin errors! This also makes device testing over a network a breeze. In a team environment like gskinner.com it wasn’t rare to have others testing bugs, regressing fixes, and checking out gameplay right off of another developer’s machine that was running a local server.

One helpful note: to test local content in Internet Explorer 10, add your IP as a trusted site in the Internet Explorer options on the Windows 8 desktop.

Online Testing

Online is the only real test. Push milestone progress up to a server and do a thorough sweep across all features and fixes in all browsers, operating systems and devices. Always clear your cache between tests (unless testing cached-specific features) and optionally quit your browsers.

FTP is slow. Check out a GIT deployment repository on your server instead using SSH, and anyone working on the project can just commit changes. We set up a script to automatically pull down the latest updates on the server, and tied it to a git commit hook for completely automated deployment! Its a few steps worthy of its own article, but it saved us an amazing amount of time.

The testing harness in the SDK provides a great way to do game testing, and includes some additional options that can lighten the load, such as:

  • quick play: A site shim script simulates the loading of the game into the site, including prompting for game modes, multiplayer, and handling game over scenarios.
  • audio-free: Audio is likely the heaviest assets in a game. Additionally, some browsers have issues with large audio files, and specific encode settings, which made it prudent to include a way to prevent any audio from loading or playing.
  • force touch: You can’t truly simulate touch – but we can at least trick the framework so touch-only controls and scenarios can be simulated on the desktop.

Push the Red Button

Strive to have the most minimal, turn-key deploy process as possible.

.. But most of that is covered for you with the SDK. We are still ironing out the 3rd-party game submission process – but are aiming for it to be as automated and straightforward as possible.

Once you’re done, visit the Game Submission section in the developer center. We will be updating this with an official submission process in the coming weeks.

And Destroy!

Thanks for making it this far! Stop reading, start building! Pick a cool title, and go have some fun. Let us know what you make, and what you’d like to see in the Atari Arcade or SDK.

Resources

Here’s some additional resources and references for game development in HTML5.

About the Authors

Lanny McNie, Michael Graves, and Chris Caldwell are the senior staff of gskinner.com, an agency focused on building bleeding edge interactive and creative, and bringing value to platform owners, developers, and end users alike. We produce success stories that showcase and enhance technology platforms. We recently worked with Atari to bring re-imagine the Atari Arcade using webstandards like HTML5, CSS3, and websockets.

This article was reprinted with permission from Microsoft Corporation. This site does business with Microsoft Corporation.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured