Using the Accelerometer in AIR for Android - Sample Application

Posted on Aug 24, 2010

accelerometer sample appAfter writing an article that should be out soon for the Adobe Edge on AIR for Android, I have become fascinated with the possibilities this opens up for Flex and Flash developers who want to develop applications for mobile. One of the first hings you may think of when developing your mobile applications, particularly if you are interested in game development, is the accelerometer. As most of you are aware, the accelerometer makes for a very useful control mechanism for many mobile games. My goal with this application was simply to understand how to use the accelerometer to move an object around the screen. It turns out that its a pretty simple task and hopefully this sample application will help you understand the values being passed from the accelerometer.

The example was built with Flash CS5 using the extensions and SDK available via the Adobe Labs preview. On a side note, I haven't programmed straight Flash in a while, so please be gentle with any suggestions for improving the code and/or optimizing it.

Moving an Object Around the Screen
The good news if you want to understand the accelerometer is that the documentation on Adobe's site already provides some great examples. In fact, the initial portions of code for this tutorial are listed straight from documentation which provides details on how to determine if the accelerometer is supported, establish the update interval and handler and even offers code that shows how to smooth out anomalies in the data it sends.

The below code utilizes all the example code from the documentation to not only post the rolling X, Y and Z values from the accelerometer to a text field to read on screen, but also moves around an object I have on screen (an image of a golf ball) based upon the X and Y accelerometer inputs (I honestly haven't figured out how to utilize the Z axis data yet for the type of motion I wanted - for a good short explanation of the different axis, check this forum reply).

if (Accelerometer.isSupported)
{
   accl = new Accelerometer();
   accl.setRequestedUpdateInterval(INTERVAL);
   accl.addEventListener(AccelerometerEvent.UPDATE,handleAccelUpdate);
}

function handleAccelUpdate(event:AccelerometerEvent) {
   accelRollingAvg(event);
   var newPosX:Number = golfBall.x - (rollingX*20);
   var newPosY:Number = golfBall.y + (rollingY*20);
   // set the text fields for tracking
   xyzText.text = "X:" + rollingX.toFixed(3) + "\nY: " + rollingY.toFixed(3) + "\nZ: " + rollingZ.toFixed(3);
   if ((newPosX > 0) && (newPosX < stage.stageWidth)) {
      golfBall.x = newPosX;
   }
   if ((newPosY > 0) && (newPosY < stage.stageHeight)) {
      golfBall.y = newPosY;
   }
}

function accelRollingAvg(event:AccelerometerEvent):void
{
   rollingX = (event.accelerationX * FACTOR) + (rollingX * (1 - FACTOR));
   rollingY = (event.accelerationY * FACTOR) + (rollingY * (1 - FACTOR));
   rollingZ = (event.accelerationZ * FACTOR) + (rollingZ * (1 - FACTOR));
}

You'll notice above that I first set the new x and y positions of my golf ball into variables before I actually set the properties on the object. I do this because I want to prevent my golf ball from being able to roll offscreen - thus the if statements around setting the x and y values for golfBall. This works well but isn't perfect yet as it doesn't account for the width of the golf ball and therefore seems to keep the ball a few pixels off the edge of the screen on the left while letting it drift halfway off-screen to the right.

Recording the Movement
Since this is mostly a learning application, I was curious to see what the values of the accelerometer were while I moved the phone around. However, I found that it was often difficult to test certain motions as I couldn't easily see the screen as I performed the action. This led me to add in a useful and kind of fun feature to my little sample application - the ability to record the accelerometer/motion data and play it back. In order to do this, I added two button on screen. The first button is the record/stop button. As you will see in the code below, clicking this button simply sets the recording mode to "recording"or "off." The other button starts and stops playback, which we will discuss in a bit.

function handleRecordButtonClick(event:MouseEvent) {
   if (recordMode == "off") {
      recording = new Array();
      recordMode = "recording";
      recordBtn.label = "STOP";
      playBtn.label = "PLAY";
   }
   else if (recordMode == "recording") {
       recordMode = "off";
       recordBtn.label = "RECORD";
   }
}

Now that we have set these recording modes, I simply modified my function that handles the accelerometer input to first check to be sure we're not in "playback" mode as in that case the object movement is handled by the playback method I will cover shortly. Secondly, if we are in "recording" mode I simply push an object containing the x, y and z rolling averages as well as the x and y position of our golf ball to an array. This array is what we'll use to play back the motion and data on screen in "playback" mode.

function handleAccelUpdate(event:AccelerometerEvent) {
   if (recordMode != "playback") {
       accelRollingAvg(event);
       var newPosX:Number = golfBall.x - (rollingX*20);
       var newPosY:Number = golfBall.y + (rollingY*20);
       // set the text fields for tracking
       xyzText.text = "X:" + rollingX.toFixed(3) + "\nY: " + rollingY.toFixed(3) + "\nZ: " + rollingZ.toFixed(3);
       if ((newPosX > 0) && (newPosX < stage.stageWidth)) {
          golfBall.x = newPosX;
       }
       if ((newPosY > 0) && (newPosY < stage.stageHeight)) {
          golfBall.y = newPosY;
       }
      
       if (recordMode == "recording") {
          var pos:Object = new Object();
          pos.posX = golfBall.x;
          pos.posY = golfBall.y;
          pos.rollingX = rollingX;
          pos.rollingY = rollingY;
          pos.rollingZ = rollingZ;
          recording.push(pos);
       }
   }
}

In order to acheive playback that matches the original motion I simply set an interval using the same value as the interval set on the accelerometer (once again, the iterval sample code came straight out of the Adobe documentation). This interval is created when you click the play button and is removed when you stop the playback (and motion control is restored to the accelerometer). Below is the handler for my play button that sets and clears the interval.

function handlePlayButtonClick(event:MouseEvent) {
    if (recordMode == "off" || recordMode == "recording") {
       recordMode = "playback";
       playBtn.label = "STOP";
       recordBtn.label = "RECORD";
       // set the playback using an interval at the same as accelerometer
       playbackPosition = 0;
       intervalId = setInterval(handlePlayback, INTERVAL);
    }
    else if (recordMode == "playback") {
       clearInterval(intervalId);
       recordMode = "off";
       playBtn.label = "PLAY";
    }
}

The interval's callback method is below. This method simply keeps track of the position in the array containing the recorded movement and sets the text as well as the x and y position of the golf ball. If we reach the end of the array, we simply start the playback back at 0 and continue playing until the play/stop button is clicked again.

function handlePlayback() {
   var playbackItem:Object = recording[playbackPosition];
   golfBall.x = playbackItem.posX;
   golfBall.y = playbackItem.posY;
   xyzText.text = "X:" + playbackItem.rollingX.toFixed(3) + "\nY: " + playbackItem.rollingY.toFixed(3) + "\nZ: " + playbackItem.rollingZ.toFixed(3);
   playbackPosition += 1;
   if (playbackPosition == recording.length) {
      playbackPosition = 0;
   }
}

Using the Application
At the moment, to install the application on your phone you will need to use the adb tool that comes with the Google Android SDK to manually add the apk (you'll also need the AIR for Android pre-release installed on your phone as well). You can also download the source FLA if you are interested in the full code.

Download the apk
Download the source

Comments

Neil I cannot get any update from the accelerometer on a HTC Desire. It is supported and is not muted, any ideas?

Posted By Neil / Posted on 02/22/2011 at 8:42 AM


Write your comment



(it will not be displayed)





About

My name is Brian Rinaldi and I am the Web Community Manager for Flash Platform at Adobe. I am a regular blogger, speaker and author. I also founded RIA Unleashed conference in Boston. The views expressed on this site are my own & not those of my employer.