How to control your HTML5 game using Arduino

Posted at September 29, 2012

Yesterday I made a mini HTML5 game based on the retro game Asteroids (here is a flashversion) without the asteroids, so I just made a ship with those controls. You can check it out on my personal site and the code is at my Github.

What about instead of using the keyboard for controls, using a potentiometer for the controls? Here is a video with me explaining it (the demo is at 8:30 into the video).

Here is the code to get it working:

The arduino code is straight from the node duino module. Read more about it in my article about duino.

Nodejs script

dependencies: node, duino, socket.io

var l = console.log;

var http = require('http');
var url  = require('url');

var io = require('socket.io').listen(1337);
io.set('log level', 1);

var arduino = require('duino');
var board = new arduino.Board({
  // debug: true
});
// defaults to a01
var pot = new arduino.Sensor({
  board: board,
});
var init = function() {
  broadcast();
}
board.on( 'ready', function() {
  // still not ready somehow
  setTimeout( init, 100 );
});

HTML file

<?php 
    header("Access-Control-Allow-Origin: *");
    header("Access-Control-Allow-Headers: *");
    header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
?>
<!doctype html>
<!--#

          Insert coin(s)

    &lt;Push any button to start&gt;

-->
<html lang=en>
    <head>
        <meta charset=utf-8>
        <meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1">
        <title>ardiono game</title>
        <style>
            body {
                background-color:black;
            }
            #game {
              position: absolute;
              top: 0px;
              left: 0px;
              z-index: -1;
            }
        </style>
    </head>
    <body>
        <canvas id=game></canvas>
        <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.10/socket.io.min.js">
        <script src="game.js"></script>
    </body>
</html>
<!--#

    GAME OVER

front end javascript (game)

(function(d, c){
  //helpers
  var getHeight = function() {
    var D = document;
    return Math.max(
        Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
        Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
        Math.max(D.body.clientHeight, D.documentElement.clientHeight)
    );
  };
  var getWidth = function() {
    var D = document;
    return Math.max(
        Math.max(D.body.scrollWidth, D.documentElement.scrollWidth),
        Math.max(D.body.offsetWidth, D.documentElement.offsetWidth),
        Math.max(D.body.clientWidth, D.documentElement.clientWidth)
    );
  };
  // polyfill: set the window.requestAnimationFrame to the browsers specific version.
  (function() {
    var lastTime = 0
      , vendors = ['ms', 'moz', 'webkit', 'o']
      , x
      , length
      , currTime
      , timeToCall;

for(x = 0, length = vendors.length; x < length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
    window.cancelAnimationFrame = 
      window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
    window.requestAnimationFrame = function(callback, element) {
        currTime = new Date().getTime();
        timeToCall = Math.max(0, 16 - (currTime - lastTime));
        lastTime = currTime + timeToCall;
        return window.setTimeout(function() { callback(currTime + timeToCall); }, 
          timeToCall);
    };
if (!window.cancelAnimationFrame)
    window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
    };

}());
  var angle = 0;
  // socket io hook
  var socket = io.connect('http://localhost:1337');
   socket.on('news', function (data) {
     // console.log(data.v);
     angle = data.v / 1024 * 8;
   });

var canvas = document.getElementById("game");
  canvas.height = getHeight();
  canvas.width = getWidth();
  // draw function is in a closure
  var draw = (function() {
    var PI = Math.PI
      , twoPI = PI * 2
      , speed = 5
      , shipX = 100
      , shipY = 100
      , degrees
      , cap = function( n, cap ) {
        return n < 0 ? n + cap : n % cap;
      }
    return function() {
      // clear the stage
      ctx.clearRect( 0, 0, canvas.width, canvas.height );
      ctx.save();
      // calc new position
      shipX += Math.sin( angle ) * speed;
      shipY -= Math.cos( angle ) * speed;
      shipX = cap( shipX, canvas.width );
      shipY = cap( shipY, canvas.height );
      // draw the changes
      // position
      ctx.translate( shipX, shipY );
      // rotate
      ctx.rotate( angle );
      // draw
      ctx.beginPath();
      ctx.fillStyle   = 'white';
      ctx.strokeStyle = 'white';
      // ship
      ctx.lineTo(0, -15);
      ctx.lineTo(10, 15);
      ctx.lineTo(0, 13);
      ctx.lineTo(-10, 15);
      // finish
      ctx.fill();
      ctx.stroke();
      ctx.closePath();
      ctx.restore();
    }
  })();
  if( canvas.getContext ) {
    var ctx = canvas.getContext("2d");
    // the loop
    (function animloop(){
        requestAnimationFrame( animloop );
        draw();
      })();
  }