Skip to content

Touchscreen D-pad with AIR for Android (part 1 of 2)

A lot of games use the directional pad or arrow keys for movement. When you move to mobile devices with only a touchscreen, you lose one of the staples of your game controls. I’ll show a simple way of getting your D-pad back and hopefully allowing you to make the transition to mobile easier.

We need to listen to the TOUCH_BEGIN, TOUCH_MOVE and TOUCH_END events. If you’re familiar with mouse events already, you can think of BEGIN as MOUSE_DOWN and END as MOUSE_UP. The biggest difference between a mouse and touch screen is that there can be multiple touches so you need to keep track of which is which. If you got three fingers on the screen and only follow the events, it’s gonna be a mess.

How to keep track of the touches then? Each touch has touchPointID associated with it so whenever a touch event is fired, you can dig it up and compare it with all your known touch IDs. For now we will use the first touch to occur and assign that for our D-pad.

Before anything else, let’s set the input mode for the Multitouch class to Touch_Point. This means Flash will only track the basic touch events like when the touch begins, when it moves and when it ends.

1
2
3
private function init():void{
  Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
}
private function init():void{
  Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
}

Then add some basic listeners for Touch events.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ... extends Sprite
 
private var dpadTouchID:int=-1;
 
public function init():void{
  Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
 
  addEventListener(TouchEvent.TOUCH_BEGIN, touchBegin);
  addEventListener(TouchEvent.TOUCH_END, touchEnd);
}
 
private function touchBegin(e:TouchEvent):void{
  dpadTouchID = e.touchPointID;
}
 
private function touchEnd(e:TouchEvent):void{
  dpadTouchID = -1;
}
// ... extends Sprite

private var dpadTouchID:int=-1;

public function init():void{
  Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;

  addEventListener(TouchEvent.TOUCH_BEGIN, touchBegin);
  addEventListener(TouchEvent.TOUCH_END, touchEnd);
}

private function touchBegin(e:TouchEvent):void{
  dpadTouchID = e.touchPointID;
}

private function touchEnd(e:TouchEvent):void{
  dpadTouchID = -1;
}

Something I’ve noticed is that touchPointID’s always start from 0 and go up. We’ll use -1 to tell when there is no touch assigned to the D-Pad.

We shouldn’t assume that there’s only gonna be one touch because there probably will be atleast 2. We’ll add some checks to make sure we’re only looking at the correct touch and add a event listener for TOUCH_MOVE so we can track the movement of the finger.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// ... extends Sprite
 
private var dpadTouchID:int=-1;
 
public function init():void{
  addEventListener(TouchEvent.TOUCH_BEGIN, touchBegin);
  addEventListener(TouchEvent.TOUCH_END, touchEnd);
  addEventListener(TouchEvent.TOUCH_MOVE, touchMove);
}
 
private function touchBegin(e:TouchEvent):void{
  if(dpadTouchID == -1){
    dpadTouchID = e.touchPointID;
  }
}
 
private function touchEnd(e:TouchEvent):void{
  if(e.touchPointID == dpadTouchID){
    dpadTouchID = -1;
  }
}
 
private function touchMove(e:TouchEvent):void{
//make sure a D-Pad touch is assigned at all, and then check if it matches
  if(dpadTouchID != -1){
    if(e.touchPointID == dpadTouchID){
      // success! let's print out the x and y!
      trace('D-Pad is moving!', e.stageX, e.stageY);
    }
  }
 
}
// ... extends Sprite

private var dpadTouchID:int=-1;

public function init():void{
  addEventListener(TouchEvent.TOUCH_BEGIN, touchBegin);
  addEventListener(TouchEvent.TOUCH_END, touchEnd);
  addEventListener(TouchEvent.TOUCH_MOVE, touchMove);
}

private function touchBegin(e:TouchEvent):void{
  if(dpadTouchID == -1){
    dpadTouchID = e.touchPointID;
  }
}

private function touchEnd(e:TouchEvent):void{
  if(e.touchPointID == dpadTouchID){
    dpadTouchID = -1;
  }
}

private function touchMove(e:TouchEvent):void{
//make sure a D-Pad touch is assigned at all, and then check if it matches
  if(dpadTouchID != -1){
    if(e.touchPointID == dpadTouchID){
      // success! let's print out the x and y!
      trace('D-Pad is moving!', e.stageX, e.stageY);
    }
  }

}

The red area shows where the touch area is for the finger, right now its overlapping right and up arrows.

Ok, now we’re tracking the D-pad touch around. It’s still pretty much acting like a mouse though. We want to use the touch tracking for a D-pad so we’ll need to figure out based on those X and Y coordinates if the finger is on top of any of the D-Pad buttons. Just for examples sake, we’ll draw a simple graphic to represent the four directional buttons. The buttons are 100×100 pixels in size. The touch area we’ll be using is going to be 60 pixels so it’s small enough to still be precise but big enough so that it can cover two buttons at a time. This way you get 8 directions easily.

Right now we’re using the 60×60 square for the finger area but TouchEvent’s have some interesting properties you might want to look into later. For example; pressure, sizeX and sizeY. Those should come in handy when creating more sophisticated controls.

Next create some simple graphics for the buttons. We’ll name them upArrow, downArrow, leftArrow and rightArrow. They should be a descendant of the DisplayObject class for this.

You want to re-check which buttons your finger is touching whenever it has moved and when it’s first pressed into the screen. So we should modify touchMove(e) and touchBegin(e) to check that.

Stay tuned for part 2!

  • http://www.kybernesis.com Ronny Anderssen

    Great tutorial!

    This is exactly what I was looking for to add in my Tetris clone.
    Looking forward to part 2 :)

  • http://www.facebook.com/profile.php?id=100003405637516 Daniel

    Thanks for the feedback DM Cook.I think I was a tlltie unclear about what the Resistance feature entails. To get a sense of Apple’s native implementation of the concept, open up your contact list (Phone > Contacts on the iPhone), place your finger on a contact’s name, and start dragging up and down without lifting your finger. Notice, it’s essentially a 1:1 ratio which I think feels right. As mentioned above the item is stuck to your finger.Now, go to the absolute top of your contact list so the My Number is 1 (555) 555-5555 and the search box are visible. Place your finger on your first contact and start to drag down without lifting your finger. See how as you drag farther down the screen, the contact that you started on is no longer under your finger? That’s the resistance I’m talking about, and I think it does provide an intuitive feel that you can’t pull any farther. Especially because as you are pulling down you can see that there is nothing past the top of the list.I agree it’s not crucial and I think there are other ways to solve the problem, but it seemed like a fun feature to implement at the time!Also, we’ve finally put the code for this online and publicly available on github. We’re calling it . Feel free to take a look and hopefully we’ll have some more documentation up soon.

  • Heh

    Hmmmmm