HTML5 Zone is brought to you in partnership with:

Austin Hallock is a co-founder of clay.io, an app store for HTML5 games and a developer API for tedious features like payment processing, social integration, leaderboards, achievements, and more. He has worked on 4 games (thus far) using HTML5: three of them can be found here, and the fourth on his blog. Austin has posted 3 posts at DZone. You can read more from them at their website. View Full User Profile

Developing a Cross-Platform HTML5 Game: Part 2

05.03.2012
| 11159 views |
  • submit to reddit

This is part 2 of a 3 part series on developing an HTML5 game with many platforms in mind. Last week I went over some of the visual and performance aspects when dealing with various screen sizes, today I want to focus on different types of input you might consider using.

Part 1: Getting the game to look great and run well across all platforms
Part 2: Handling the various input types of each platform
Part 3: Dealing with security for your game

Part 2 covers:

  • Case Studies of input in our 3 HTML5 games using:
    • Keyboard
    • Mouse
    • Touch
    • Accelerometer

Because HTML5 allows you to develop games for multiple platforms, it makes sense to cater to the different inputs of each one. Mobile phones give you access to features like the accelerometer while desktops have keyboards -- both are great, and both should be utilized if it makes sense for your game.

The real key is to be creative - which if you're a game designer, you definitely have that quality. Typically in game development you're limited to one or two types of input. With HTML5 you're no longer trapped beneath those restrictions, be adventurous and take full advantage of the technology.

Meshing Keyboard, Mouse, and Touch Events

When developing a cross-platform game, you're no longer dealing with just keyboard and mouse input, or just touch input -- you have to take both into account.

How you handle these various input methods certainly depends on the type of game you have. Below is how we catered three of the games on Clay.io to different devices through creative use of input.




Word Wars is a game where you try to find the most words in a jumbled mix of letters.

For desktops, we accept both keyboard and mouse as input. Words can be typed, or the player can drag and select the tiles to form a word. Clicking and dragging might be nice for some, but it feels a bit cumbersome compared with simply typing words as you see them.

I was going to paste in the code we have for this, but honestly it's a bit boring, and not very elegant since it was written in a 24 hour hackathon. I'll paraphrase. If you want to get down and dirty in some code, read the next section on what we did for Slime Volley.

  1. We attach keydown and keyup events to the canvas element
    1. For each new keydown, we verify that it's a valid letter (adjacent to the previous letter)
      1. If it's valid, we highlight the new letter and add to an array of selected letters
      2. If it's invalid, we clear the letters
    2. We also listen for when the "enter" key is pressed (e.keyCode === 13)
      1. If so, we check to see if the letters in our array make up a valid word for this board, then clear the letters
    3. If backspace is pressed (e.keyCode === 8) we pop the last letter in our selected keys array (and cancel the browser back button functionality with e.preventDefault())
    4. It's important to prevent the default action on key events for space and backspace, otherwise space will act as "page down" and backspace will go to the previous page in the browser history. I've seen this ignored in a few games, and it made them unplayable on a screen without much vertical height
  2. We attach mousedown, mousemove and mouseup events to the canvas element
    1. Mousedown and mousemove select a tile based on the x, y coordinates
    2. Mouseup checks if the word selected is valid or not, then clears the letters
  3. We attach touchstart, touchmove and touchend events to the canvas element
    1. Coordinates within the page are found with event.touches[0].pageX (and pageY)
    2. If you're using what I wrote about for retina devices in my last post, be sure to multiply the coordinate by window.devicePixelRatio
    3. Touchstart and touchmove are equivalent mousedown and mousemove above
    4. Touchend is equivalent to mouseup

 

 

Slime Volley is a remake of an older Java game called Slime Volleyball. You control the left slime, and can move back and forth, or jump, to prevent the ball from landing on your side.

The entire source code up on GitHub, so be sure to have a look (do note that it's written in CoffeeScript not JavaScript). Most of what you'll want to look at is in the /src directory.

In this game it made sense to have WASD and arrow keys as input on desktops - we just needed 3 actions: left, right and jump. That was easy enough and was implemented in our input class: /src/shared/input.coffee

handleKeyDown = (e) =>
    @keys['key'+normalizeKeyEvent(e).which] = true
handleKeyUp = (e) =>
    @keys['key'+normalizeKeyEvent(e).which] = false


Later we can tell if, say, the left arrow key, is down with @keys[‘key37'] which is a boolean true/false.

Since no arrow keys available on a mobile device, we had to create a special UI for the three actions we allow. You can see it in the screenshot above, and the code is located in /src/shared/lib/gamepad.coffee. You can choose to have this only show on mobile devices with some media queries, or even detect touch with some JavaScript.

// props to http://stackoverflow.com/a/4819886
function is_touch_device()  {
    return !!('ontouchstart' in window) ? 1 : 0;
}


Our ‘gamepad' (the UI we created) also uses multi-touch, and touch gestures so you're able to move left/right by sliding your finger, as well as jump at the same time.

The code for being able to slide from button to button is in gamepad.coffee, it basically detects ontouchmove with the coordinates if you're in the same box, or a new one, and acts accordingly.

Here's what we have for handling multi-touch:

# multitouch shim wraps a callback and applies it for each individual touch
# If you're not familiar with coffeescript, (callback) ->
    is equivalent to function(callback) {}
# Also note that someFunc param1, param2 is equivalent to someFunc( param1, param2 )
multitouchShim = (callback) ->
    return ((cb) ->  # create a scope to protect the callback param
return (e) ->
    e.preventDefault()
cb( x: t.clientX, y: t.clientY, identifier: t.identifier ) for t in e.changedTouches
return
).call(this, callback)

canvas.addEventListener 'touchstart', multitouchShim(handleMouseDown), true
canvas.addEventListener 'touchend',  multitouchShim(handleMouseUp), true
canvas.addEventListener 'touchmove', multitouchShim(handleMouseMove), true
canvas.addEventListener 'touchcancel', multitouchShim(handleMouseUp), true


You're more than welcome to use the entire src/shared/lib directory for your game as well!

 

 




Falldown is a game that's been done countless times before on every device you can imagine (I spent a good portion of my high school classes playing this on my TI-83). The main idea is you control a ball and have to get through the gaps so you don't hit the top.

Like Slime Volley, there are only three things you can do, move left, move right, and jump. Clearly the best way to go about this was to use the arrow keys for desktops again. However, rather than implement a UI for this on mobile, we chose to use the accelerometer, something I haven't seen utilized very much in the browser.

Accelerometer Support

Implementing accelerometer support is actually quite simple. You just listen for the devicemotion event, (similar to how you would for mousemove). The callback function receives a DeviceMotionEvent object that contains information about the acceleration in all three planes (x, y, z)

Here's the code taken directly from Falldown (which is more or less the simplest use case of accelerometer)

window.onDeviceMotion = function(e) {
    var x_accel;
    // Portrait
    if(window.orientation == 0 || window.orientation == 180)
        x_accel = e.accelerationIncludingGravity.x;
    // Landscape
    else
        x_accel = e.accelerationIncludingGravity.y;

    // Reverse left and right if the phone is flipped (upside-down landscape or upside-down portrait)
    if(window.orientation == 90 || window.orientation == 180) 
        x_accel *= -1;
  
    // If it's tilted more than just a little bit, move the ball in that direction
    if(x_accel > 0.5)
    {
        de.keys.right = true; // equivalent of right arrow key pressed
        de.keys.left = false;
    }
    else if(x_accel < -0.5)
    {
        de.keys.left = true; // equivalent of left arrow key pressed
        de.keys.right = false;
    }
    else
    {
        de.keys.left = de.keys.right = false; // no tilt in device, so unset both left & right keys
    }
};
window.addEventListener("devicemotion", onDeviceMotion, false);


Note how we had to use a different axis (y instead of x) for landscape, and we had to reverse the numbers if the phone was ‘upside-down'.


The real key to handling input across multiple devices is being creative with your options. Pick the forms of input that make the most sense for your game and implement them, it's really not difficult, nor very time consuming, and will vastly improve your game on each device.

Here are some of your many options for input:
  • Keyboard
  • Mouse
  • Touch events
  • Multi-touch events
  • Accelerometer
  • Gamepad (one of my favorite HTML5 APIs, here's a great tutorial)

Pick a couple and implement them in your awesome new HTML5 game!

In part three of this series, I will cover security and a backend for your HTML5 game - stuff I've gotten very familiar with in developing two games with backends, and having to find a secure way to pass data (like high scores and user info) back and forth for Clay.io.
Published at DZone with permission of its author, Austin Hallock.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)