Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 1129969 of Unconventional controls

  • Revision slug: Games/Techniques/Control_mechanisms/Other
  • Revision title: Unconventional controls
  • Revision id: 1129969
  • Created:
  • Creator: end3r
  • Is current revision? No
  • Comment Leap Motion paragraph updated

Revision Content

{{PreviousMenu("Games/Techniques/Control_mechanisms/Desktop_with_gamepad", "Games/Techniques/Control_mechanisms")}}

Having different control mechanisms in your game helps reach broader audiences. Implementing mobile and desktop controls is recommended is a must, and gamepad controls add that extra experience. But imagine going even further — in this article we will explore various unconventional ways to control your web game, some more unconventional than others.

TV remote

Playing games on a TV screen doesn't always have to be done through consoles. There's already a Gamepad API working on the desktop computers, so we can imitate the experience, but we can go even further. Modern smart TVs can handle HTML5 games, because they have a built-in browser that can be used as a gaming platform. Smart TVs are shipped with remote controls, which can be used to control your games if you know how.

The earliest demo of Captain Rogers: Battle at Andromeda was adjusted to work on a huge TV. Interestingly enough, the first Captain Rogers game (Asteroid Belt of Sirius) was optimized for low-end, small-screen, cheap smartphones running Firefox OS, so you can see the difference three years can make — you can read the whole story in our Building games for Firefox OS TV Hacks post.

Panasonic TV remote controls for the game Captain Rogers: Battle at Andromeda.

Using a TV remote to control the game ended up being surprisingly easy, because the events fired by the controller are emulating conventional keyboard keys. Captain Rogers had the keyboard controls implemented already:

this.cursors = this.input.keyboard.createCursorKeys();
//...
if(this.cursors.right.isDown) {
    // move player right
}

It works out of the box. The cursors are the four directional arrow keys on the keyboard, and these have exactly the same key codes as the arrow keys on the remote. How do you know the codes for the other remote keys? You can check them by printing the responses out in the console:

window.addEventListener("keydown", function(event) {
    console.log(event.keyCode);
}, this);

Every key pressed on the remote will show its key code in the console. You can also check this handy cheat sheet if you're working with Panasonic TVs running Firefox OS:

Remote control key codes for Panasonic TV.

You can add moving between states, starting a new game, controlling the ship and blowing stuff up, pausing and restarting the game. All that is needed is checking for key presses:

window.addEventListener("keydown", function(event) {
    switch(event.keyCode) {
        case 8: {
            // pause the game
            break;
        }
        case 588: {
            // detonate bomb
            break;
        }
        // ...
    }
}, this);

You can see it in action by watching this video.

Leap Motion

Have you ever thought about controlling a game only with your hands? It's possible with Leap Motion, an immersive controller for games and apps.

It's more and more popular due to very good integration with VR headsets — demoing Rainbow Membrane on an Oculus Rift with Leap Motion attached to it was voted one of the best WebVR experiences by JavaScript developers visiting demo booths at conferences around the world.

As well as being great for virtual interfaces, it can also be used for a casual 2D gaming experirence. It would be very difficult to do everything with only your hands, but it's totally doable for the simple Captain Roger's gameplay — steering the ship and shooting the bullets.

There's good Hello World and Getting Started JavaScript tutorials available on the Leap Motion documentation pages, which will get you through the basics. You can also check the tutorial about using Leap Motion plugin for Kiwi.js, or the case study of building a web game with Leap Motion and Pixi.js. Be sure to visit the LeapJS repository on GitHub to learn about the JavaScript client for the Leap Motion controller and read the documentation there. If all else fails, there's also a gallery of working examples which you can check yourself.

To have the Leap Motion working on your computer you have to first install it by following the steps at leapmotion.com/setup. When everything is installed and the controller is connected to your computer we can proceed implementing the support in our little demo. First, add the <srcipt> tag with the url pointing at this file, and add <div id="output"></div> just before the closing </body> tag for testing our output information.

We will need a few helper variables for our code to work - one for the purpose of calculating the degrees from radians, two for holding the information about the horizontal and vertical amount of degrees our hand is leaned above the controller, one for the threshold of that lean, and one for the state of our hand's grab status. Add those lines after all the event listeners for keyboard and mouse, but before the draw method:

var toDegrees = 1 / (Math.PI / 180);
var horizontalDegree = 0;
var verticalDegree = 0;
var degreeThreshold = 30;
var grabStrength = 0;

Then right after that we will use the Leap's loop method to get the information held in the hand variable on every frame:

Leap.loop({
    hand: function(hand) {
        horizontalDegree = Math.round(hand.roll() * toDegrees);
        verticalDegree = Math.round(hand.pitch() * toDegrees);
        grabStrength = hand.grabStrength;
        output.innerHTML = 'Leap Motion: <br />'
            + ' roll: ' + horizontalDegree + '° <br />'
            + ' pitch: ' + verticalDegree + '° <br />'
            + ' strength: ' + grabStrength + '';
    }
});

The code above is calculating and assigning the horizontalDegree, verticalDegree and grabStrength values that we will use later on, and outputting it in HTML to see the actual values. When those variables are up-to-date, we can use them in the draw function to move the ship:

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // ...

    if(horizontalDegree > degreeThreshold) {
        playerX -= 5;
    }
    else if(horizontalDegree < -degreeThreshold) {
        playerX += 5;
    }
    if(verticalDegree > degreeThreshold) {
        playerY += 5;
    }
    else if(verticalDegree < -degreeThreshold) {
        playerY -= 5;
    }
    if(grabStrength == 1) {
        alert('BOOM!');
    }

    ctx.drawImage(img, playerX, playerY);
    requestAnimationFrame(draw);
}

If the horizontalDegree is greater than our degreeThreshold, which is 30 in this case, then the ship will be moved left 5 pixels. It will move left on every frame if the horizontalDegree is greater than the threshold. If it's value is lower than the threshold's negative value, then the ship is moved right. It goes very similar for top/down movement. The last value is grabStrength, which is a float between 0 and 1 - when reaching 1 (fist fully clenched), we will show the alert which in a full game can be replaced with the shooting logic.

Leap Motion controller support in the game, with visible output for roll, pitch and strength.

That's it - everything you needed for a working Leap Motion example in JavaScript is here already. You can explore the hand's properties and implement any behaviour you like right inside your game.

Voice

Instead of using your hands to control the game, maybe you could do the same thing a little bit differently? Think of a little experiment: shooting by shouting. You could develop a special version of the game where shooting is done by shouting into the microphone. It sounds crazy, and won't make much sense in a long run, but it's an interesting approach nonetheless.

You can go even further and try to implement voice commands with the Web Speech API. Instead of clicking the button dropping the bomb you could say 'detonate' and it would work without touching anything. It would work best in a 3D environment where on-screen display is a tricky topic, so having voice commands would help a lot, but it's still an option in simple 2D games — if not for the movement, then at least for all the other actions.

There's an interesting article available on Using the Web Speech API which covers the basics on the topic. The demo includes a grammar list of recognized words the speech recognition script can use.

Doppler effect

There's a very interesting article available on Motion sensing using the doppler effect, which includes mixing the two previous approaches: waving your hand and using the microphone. This time it's about detecting sound waves bouncing off objects and returning to the microphone.

Doppler effect as a way to control the scroll of an article on a laptop using hand gesture.

If the frequency of the bounced sound is shifted from the original one, then we can detect that the movement of that object occured. That way we can detect a hand movement by using only a built-in microphone!

This can be accomplished using a small library created by Daniel Rapp — it can be as simple as calculating the difference between two frequencies:

doppler.init(function(bandwidth) {
    var diff = bandwidth.left - bandwidth.right;
});

The diff would be the difference between the initial position of the hand and the final one.

It won't give us the full flexibility of using a Gamepad, or even Leap Motion, but it's definitely an interesting, unconventional alternative. You can use it to scroll a page hands-free, or play theremin, but it should also be enough to move the ship on the screen up and down if implemented correctly.

Proximity API

Another interesting idea is to use the built-in proximity sensors of your hardware to detect how far an object, for example a hand, is from the given sensor. It could work similar to the doppler effect in terms of manipulating the player's ship on the screen by moving your hand closer or further from the device.

An event listener for device proximity would look like this:

window.addEventListener('deviceproximity', function(event) {
    var min = event.min;
    var max = event.max;
    var proximity = event.value;
});

The min and max values are the minimum and the maximum distances respectively between which the sensor can detect the exact proximity value. All three are calculated in centimetres.

Note: See the {{domxref("DeviceProximityEvent")}} reference page for more details.

MaKey MaKey

If you want to go completely bananas you can use MaKey MaKey, a board that can turn anything into a controller — it's all about connecting real-world, conductive objects to a computer and using them as touch interfaces.

Controlling a banana piano using Makey Makey.

Check out the banana piano video, and be sure to visit the quick start guide for all the needed info.

There's even a Cylon.js-supported Makey Button functionality inspired by the MaKey MaKey board, so you can use this widely popular robotics framework for your experiments with Arduino or Raspberry Pi. Connecting the boards and using them may look like this:

var Cylon = require('cylon');
Cylon.robot({
  connections: {
    arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
  },
  devices: {
    makey: { driver: 'makey-button', pin: 2 }
  },
  work: function(my) {
    my.makey.on('push', function() {
      console.log("Button pushed!");
    });
  }
}).start();

As the description says: this GPIO driver allows you to connect a 10 MOhm resistor to a digital pin on your Arduino or Raspberry Pi to control your robots with bananas, clay, or drawable circuitry.

Summary

I hope you liked the experiments — if you have any others that you think might interest other people, feel free to add details of them here.

And remember: have fun making games!

{{PreviousMenu("Games/Techniques/Control_mechanisms/Desktop_with_gamepad", "Games/Techniques/Control_mechanisms")}}

Revision Source

<p>{{PreviousMenu("Games/Techniques/Control_mechanisms/Desktop_with_gamepad", "Games/Techniques/Control_mechanisms")}}</p>

<p class="summary">Having different control mechanisms in your game helps reach broader audiences. Implementing mobile and desktop controls is recommended is a must, and gamepad controls add that extra experience. But imagine going even further — in this article we will explore various unconventional ways to control your web game, some more unconventional than others.</p>

<h2 id="TV_remote">TV remote</h2>

<p>Playing games on a TV screen doesn't always have to be done through consoles. There's already a Gamepad API working on the desktop computers, so we can imitate the experience, but we can go even further. Modern smart TVs can handle HTML5 games, because they have a built-in browser that can be used as a gaming platform. Smart TVs are shipped with remote controls, which can be used to control your games if you know how.</p>

<p>The earliest demo of <a class="external external-icon" href="https://rogers2.enclavegames.com/demo/">Captain Rogers: Battle at Andromeda</a> was adjusted to work on a huge TV. Interestingly enough, the first Captain Rogers game (Asteroid Belt of Sirius) was optimized for low-end, small-screen, cheap smartphones running Firefox OS, so you can see the difference three years can make — you can read the whole story in our <a href="https://hacks.mozilla.org/2016/01/building-games-for-firefox-os-tv/">Building games for Firefox OS TV</a> Hacks post.</p>

<p><img alt="Panasonic TV remote controls for the game Captain Rogers: Battle at Andromeda." src="https://mdn.mozillademos.org/files/14127/controls-tvremote.png" style="height:380px; width:575px" /></p>

<p>Using a TV remote to control the game ended up being surprisingly easy, because the events fired by the controller are emulating conventional keyboard keys. Captain Rogers had the keyboard controls implemented already:</p>

<pre>
this.cursors = this.input.keyboard.createCursorKeys();
//...
if(this.cursors.right.isDown) {
    // move player right
}</pre>

<p>It works out of the box. The cursors are the four directional arrow keys on the keyboard, and these have exactly the same key codes as the arrow keys on the remote. How do you know the codes for the other remote keys? You can check them by printing the responses out in the console:</p>

<pre>
window.addEventListener("keydown", function(event) {
    console.log(event.keyCode);
}, this);</pre>

<p>Every key pressed on the remote will show its key code in the console. You can also check this handy cheat sheet if you're working with Panasonic TVs running Firefox OS:</p>

<p><img alt="Remote control key codes for Panasonic TV." src="https://mdn.mozillademos.org/files/14129/controls-tvkeys.png" style="height:506px; width:575px" /></p>

<p>You can add moving between states, starting a new game, controlling the ship and blowing stuff up, pausing and restarting the game. All that is needed is checking for key presses:</p>

<pre class="js">
window.addEventListener("keydown", function(event) {
    switch(event.keyCode) {
        case 8: {
            // pause the game
            break;
        }
        case 588: {
            // detonate bomb
            break;
        }
        // ...
    }
}, this);</pre>

<p>You can see it in action by watching <a href="https://www.youtube.com/watch?v=Bh11sP0bcTY">this video</a>.</p>

<h2 id="Leap_Motion">Leap Motion</h2>

<p>Have you ever thought about controlling a game only with your hands? It's possible with <a href="https://www.leapmotion.com/">Leap Motion</a>, an immersive controller for games and apps.</p>

<p>It's more and more popular due to very good integration with VR headsets — demoing <a href="https://mozvr.com/webvr-demos/demos/rainbowmembrane/">Rainbow Membrane</a> on an Oculus Rift with Leap Motion attached to it was voted one of the best WebVR experiences by JavaScript developers visiting demo booths at conferences around the world.</p>

<p>As well as being great for virtual interfaces, it can also be used for a casual 2D gaming experirence. It would be very difficult to do everything with only your hands, but it's totally doable for the simple Captain Roger's gameplay — steering the ship and shooting the bullets.</p>

<p>There's good <a href="https://developer.leapmotion.com/documentation/javascript/devguide/Sample_Tutorial.html">Hello World</a> and <a href="https://developer.leapmotion.com/getting-started/javascript">Getting Started</a> JavaScript tutorials available on the Leap Motion documentation pages, which will get you through the basics. You can also check the tutorial about <a href="https://gamedevelopment.tutsplus.com/tutorials/add-motion-control-to-a-kiwijs-game-with-the-leap-motion-controller--cms-20455">using Leap Motion plugin for Kiwi.js</a>, or the case study of <a href="https://arstechnica.com/business/2014/04/building-a-gesture-controlled-web-game-with-leap-motion/">building a web game with Leap Motion and Pixi.js</a>. Be sure to visit the <a href="https://github.com/leapmotion/leapjs">LeapJS repository on GitHub</a> to learn about the JavaScript client for the Leap Motion controller and read the documentation there. If all else fails, there's also a <a href="https://developer.leapmotion.com/gallery/category/javascript">gallery of working examples</a> which you can check yourself.</p>

<p>To have the Leap Motion working on your computer you have to first install it by following the steps at <a href="https://leapmotion.com/setup">leapmotion.com/setup</a>. When everything is installed and the controller is connected to your computer we can proceed implementing the support in our <a href="https://github.com/end3r/JavaScript-Game-Controls/">little demo</a>. First, add the <code>&lt;srcipt&gt;</code> tag with the <code>url</code> pointing at <a href="https://js.leapmotion.com/leap-0.6.4.min.js">this file</a>, and add <code>&lt;div id="output"&gt;&lt;/div&gt;</code> just before the closing <code>&lt;/body&gt;</code> tag for testing our output information.</p>

<p>We will need a few helper variables for our code to work - one for the purpose of calculating the degrees from radians, two for holding the information about the horizontal and vertical amount of degrees our hand is leaned above the controller, one for the threshold of that lean, and one for the state of our hand's grab status. Add those lines after all the event listeners for keyboard and mouse, but before the <code>draw</code> method:</p>

<pre class="js">
var toDegrees = 1 / (Math.PI / 180);
var horizontalDegree = 0;
var verticalDegree = 0;
var degreeThreshold = 30;
var grabStrength = 0;</pre>

<p>Then right after that we will use the Leap's <code>loop</code> method to get the information held in the <code>hand</code> variable on every frame:</p>

<pre class="js">
Leap.loop({
    hand: function(hand) {
        horizontalDegree = Math.round(hand.roll() * toDegrees);
        verticalDegree = Math.round(hand.pitch() * toDegrees);
        grabStrength = hand.grabStrength;
        output.innerHTML = 'Leap Motion: &lt;br /&gt;'
            + ' roll: ' + horizontalDegree + '° &lt;br /&gt;'
            + ' pitch: ' + verticalDegree + '° &lt;br /&gt;'
            + ' strength: ' + grabStrength + '';
    }
});</pre>

<p>The code above is calculating and assigning the <code>horizontalDegree</code>, <code>verticalDegree</code> and <code>grabStrength</code> values that we will use later on, and outputting it in HTML to see the actual values. When those variables are up-to-date, we can use them in the <code>draw</code> function to move the ship:</p>

<pre class="js">
function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // ...

    if(horizontalDegree &gt; degreeThreshold) {
        playerX -= 5;
    }
    else if(horizontalDegree &lt; -degreeThreshold) {
        playerX += 5;
    }
    if(verticalDegree &gt; degreeThreshold) {
        playerY += 5;
    }
    else if(verticalDegree &lt; -degreeThreshold) {
        playerY -= 5;
    }
    if(grabStrength == 1) {
        alert('BOOM!');
    }

    ctx.drawImage(img, playerX, playerY);
    requestAnimationFrame(draw);
}</pre>

<p>If the <code>horizontalDegree</code> is greater than our <code>degreeThreshold</code>, which is 30 in this case, then the ship will be moved left 5 pixels. It will move left on every frame if the <code>horizontalDegree</code> is greater than the threshold. If it's value is lower than the threshold's negative value, then the ship is moved right. It goes very similar for top/down movement. The last value is <code>grabStrength</code>, which is a float between 0 and 1 - when reaching 1 (fist fully clenched), we will show the alert which in a full game can be replaced with the shooting logic.</p>

<p><img alt="Leap Motion controller support in the game, with visible output for roll, pitch and strength." src="https://mdn.mozillademos.org/files/14161/controls-leapmotion.png" style="height:474px; width:600px" /></p>

<p>That's it - everything you needed for a working Leap Motion example in JavaScript is here already. You can explore the <code>hand</code>'s properties and implement any behaviour you like right inside your game.</p>

<h2 id="Voice">Voice</h2>

<p>Instead of using your hands to control the game, maybe you could do the same thing a little bit differently? Think of a little experiment: shooting by shouting. You could develop a special version of the game where shooting is done by shouting into the microphone. It sounds crazy, and won't make much sense in a long run, but it's an interesting approach nonetheless.</p>

<p>You can go even further and try to implement voice commands with the Web Speech API. Instead of clicking the button dropping the bomb you could say <em>'detonate'</em> and it would work without touching anything. It would work best in a 3D environment where on-screen display is a tricky topic, so having voice commands would help a lot, but it's still an option in simple 2D games — if not for the movement, then at least for all the other actions.</p>

<p>There's an interesting article available on <a href="/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API">Using the Web Speech API</a> which covers the basics on the topic. The demo includes a grammar list of recognized words the speech recognition script can use.</p>

<h2 id="Doppler_effect">Doppler effect</h2>

<p>There's a very interesting article available on <a href="https://danielrapp.github.io/doppler/">Motion sensing using the doppler effect</a>, which includes mixing the two previous approaches: waving your hand and using the microphone. This time it's about detecting sound waves bouncing off objects and returning to the microphone.</p>

<p><img alt="Doppler effect as a way to control the scroll of an article on a laptop using hand gesture." src="https://mdn.mozillademos.org/files/14131/controls-doppler.png" style="height:324px; width:575px" /></p>

<p>If the frequency of the bounced sound is shifted from the original one, then we can detect that the movement of that object occured. That way we can detect a hand movement by using only a built-in microphone!</p>

<p>This can be accomplished using <a href="https://github.com/DanielRapp/doppler">a small library</a> created by Daniel Rapp — it can be as simple as calculating the difference between two frequencies:</p>

<pre>
doppler.init(function(bandwidth) {
    var diff = bandwidth.left - bandwidth.right;
});</pre>

<p>The <code>diff</code> would be the difference between the initial position of the hand and the final one.</p>

<p>It won't give us the full flexibility of using a Gamepad, or even Leap Motion, but it's definitely an interesting, unconventional alternative. You can use it to scroll a page hands-free, or play theremin, but it should also be enough to move the ship on the screen up and down if implemented correctly.</p>

<h2 id="Proximity_API">Proximity API</h2>

<p>Another interesting idea is to use the built-in proximity sensors of your hardware to detect how far an object, for example a hand, is from the given sensor. It could work similar to the doppler effect in terms of manipulating the player's ship on the screen by moving your hand closer or further from the device.</p>

<p>An event listener for device proximity would look like this:</p>

<pre>
window.addEventListener('deviceproximity', function(event) {
    var min = event.min;
    var max = event.max;
    var proximity = event.value;
});</pre>

<p>The <code>min</code> and <code>max</code> values are the minimum and the maximum distances respectively between which the sensor can detect the exact <code>proximity</code> value. All three are calculated in centimetres.</p>

<div class="note">
<p><strong>Note</strong>: See the {{domxref("DeviceProximityEvent")}} reference page for more details.</p>
</div>

<h2 id="MaKey_MaKey">MaKey MaKey</h2>

<p>If you want to go completely bananas you can use <a href="https://makeymakey.com/">MaKey MaKey</a>, a board that can turn anything into a controller — it's all about connecting real-world, conductive objects to a computer and using them as touch interfaces.</p>

<p><img alt="Controlling a banana piano using Makey Makey." src="https://mdn.mozillademos.org/files/14133/controls-banana.png" style="height:323px; width:575px" /></p>

<p>Check out the <a href="https://www.youtube.com/watch?v=_DWQ6ce2Ags">banana piano video</a>, and be sure to visit the <a href="https://learn.sparkfun.com/tutorials/makey-makey-quickstart-guide">quick start guide</a> for all the needed info.</p>

<p>There's even a <a href="https://cylonjs.com/documentation/drivers/makey-button/">Cylon.js-supported Makey Button functionality</a> inspired by the MaKey MaKey board, so you can use this widely popular robotics framework for your experiments with Arduino or Raspberry Pi. Connecting the boards and using them may look like this:</p>

<pre>
var Cylon = require('cylon');
Cylon.robot({
  connections: {
    arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
  },
  devices: {
    makey: { driver: 'makey-button', pin: 2 }
  },
  work: function(my) {
    my.makey.on('push', function() {
      console.log("Button pushed!");
    });
  }
}).start();</pre>

<p>As the description says: this GPIO driver allows you to connect a 10 MOhm resistor to a digital pin on your Arduino or Raspberry Pi to control your robots with bananas, clay, or drawable circuitry.</p>

<h2 id="Summary">Summary</h2>

<p>I hope you liked the experiments — if you have any others that you think might interest other people, feel free to add details of them here.</p>

<p>And remember: have fun making games!</p>

<p>{{PreviousMenu("Games/Techniques/Control_mechanisms/Desktop_with_gamepad", "Games/Techniques/Control_mechanisms")}}</p>
Revert to this revision