Thus!: I present this here write-up of a project I tasked myself with earlier in the year; to achieve a number of the things I’m very comfortable with in AS3, but using JS and the canvas element as the primary technologies.
A simple and familiar premise: using a mouse pointer or finger, move the left paddle to keep the
ball block out of the gutter and hold-out until the CPU player can’t keep up with your incredible reaction times. The first player to reach 10 points wins the game, to little or no fanfare.
Due to the number of developers transitioning from Flash/AS3 to HTML5 right now, a number of technologies, methodologies and perhaps some other -ologies have been created to ease the process and help map skills to these new disciplines. Specifically, I’m thinking of cross-compiling languages, some of the Adobe Edge tools, and JS suites/libraries geared towards this. I looked into a good few of these, but was left with the uncomfortable feeling that, to varying degrees, they obfuscated what went on behind the scenes. Higher level solutions have their appeal (and I honestly don’t like working more than I need to), but it inevitably becomes necessary to implement behaviour outside of the scope of these aids, or at least to know how and why they work the way they do. It’s not that I expected to run into such scope issues while making a crappy Pong clone, but as this was a learning exercise, it paid to avoid any easy, abstracted solutions.
I also wanted this to be very mobile-friendly; perhaps the primary reason for Flash being shunned so severely was its shaky (and actively shaken) mobile presence, in conjunction with the massive surge in web consumption on portable devices. I’m not doing myself any favours if the game runs on only a couple of desktops/browsers. (Although on a related note, today’s front-end web developer has more to worry about from low adoption of modern HTML5-compliant browsers than from the rather impressive Flash Player penetration, but once again the mobile factor makes this less applicable.)
Almost all the coding for this project was completed in Sublime Text 2, due to its lightweight footprint, syntax highlighting, unobtrusive completion, and – I’m ashamed to say – the sexiest colour scheme I’ve seen in a text editor. I also dabbled with JetBrains’ Webstorm IDE, but found it unnecessarily bloated for this scale of project. Partly, I think I missed the conveniences of FlashDevelop, and resented the trifling, arbitrary differences, which are somehow easier to ignore in a bare bones text editor. I’ll be giving Webstorm another shake down the line though.
I tested primarily on Win8+Chrome, and ran my mobile tests on an iPhone 4S, an Android Nexus 7 tablet, and a Blackberry Z10. For the iPhone and tablet, I tried out Adobe’s Edge Inspect, but sadly found it to provide little insight or purpose beyond conventional device-browser testing. The remote inspection was the most attractive feature, but it turned out to be only partially supported and unreliable beyond that. I was later able to debug an iDevice issue in OS X by using Apple’s iOS Simulator, bundled with Xcode.
For the early iterations, my graphics consisted of calls to
canvas.getContext("2d").fillRect() to draw white rectangles on a black background. This is more than adequate for a Pong clone but not suitable for most real-world projects with any kind of art direction (although flat design is à la mode…), so I drew up some assets in Photoshop:
- A paddle
- A ‘ball’
- Digits 0 – 9
- A frame for the play-area
- Some CRT monitor -style scanlines
…And gave all the main assets a retro green monitor glow, laid each one out in place, then exported it as a homebrew spritesheet. From there, the
fillRect() calls were replaced by those to
canvas.getContext("2d").drawImage(), which allows sampling a specified area from a loaded image asset, transforming it and drawing it into the canvas.
One of the biggest challenges I ran into while building the game was getting the sound effects to play consistently across every device. Audio support is still one of HTML5′s weakest areas, when compared directly to Flash. Support and behaviour varies greatly across platforms, with iOS Safari being the most troublesome. In the end, I settled on the following configuration:
- Audio is initialised and loaded in only upon the first user interaction (mouse pointer or touch) event, as the mobile browsers disallow playback that’s not seen to be ordained by the user
- The Web Audio API is used as the primary playback mechanism, due to its relatively low latency and versatility
- Older HTML5 audio tags are used where Web Audio is unavailable
Chrome for desktop was the most accommodating, and played back both audio forms with no issues. On Android to date, only the beta version of Chrome has support for Web Audio, but with this enabled performance is great; with the fallback, sound is badly delayed. On iOS Safari, Web Audio works fine once unlocked with a user input event, but audio element tags are hopeless: only one such clip can be loaded into a given page for playback. Blackberry 10′s browser also played audio well, but I didn’t bother to check which method it was using. I merely shouted, “Music to my ears!”, and tossed the phone back to my wife.
I hope that proves to be of some use to fellow weary ex-AS3 devs, blowing into town on the advice of Old Man Google. The game uploaded here has the minified code, but to have a proper dig around, feel free to check out the GitHub version. Any questions or comments will be answered gladly. Thanks!
Chrome changed its implementation of the Web Audio API to stop recognising the (now deprecated) ‘noteOn’ and ‘noteOff’ functions, in favour of ‘start’ and ‘stop’. So that has been updated here and on GitHub. I also added a new CRT-scan effect to the design.