Freigeben über


Adding Touch support to a Windows 8 Metro Style App using HTML and JavaScript

Overview

I have recently been coding a Windows 8 Metro Style App using the new Windows 8 Release Preview bits and Visual Studio Express 2012 RC.  The app is going to be a retro shooter that takes advantage of HTML5 Canvas for the main game engine and then several Windows 8 Metro Style App Features. 

I wanted to add Touch Support to the game enabling players to use their fingers to destroy the on screen ships.  This meant supporting multiple fingers on screen at the same time as well still supporting mouse for players who did not own a touch device.  Thankfully this is super easy to do via the MSPointer API’s!

 

Pointer

 

These API’s will handle all touch and mouse events thus simplifying the events you need to handle.

MSPointerDown
MSPointerMove
MSPointerUp
MSPointerOver
MSPointerOut

You can also handle Gestures such as Tap Events using the following:

MSGestureTap - The user taps on the screen with touch or pen, or clicks the mouse.
MSGestureDoubleTap - The user taps two times (within a time threshold) on the screen with touch or pen, or double-clicks the mouse.
MSGestureHold - The user presses and holds a finger on the screen without moving.
MSGestureStart, MSGestureChange, and MSGestureEnd – Handle your own custom gestures

 

For my game I chose to handle the MSPointerUp event.  This means that any time a user taps the screen with a finger (or clicks the mouse button) when they release an event will fire off.  These events will pass along the x and y locations that they touched.  It is important to keep in mind that a user will be able to drag their finger around without the event being registered.  We only handle the x and y locations when they finally remove their finger “up” from the screen. 


Handling Touch Events

The first thing I did was to tell my application which element to monitor touch events on.  My game is entirely HTML5 Canvas based (more on canvas game development to come) so I handled all touch events on the Canvas like this:

 //Handle Touch
 canvas.addEventListener("MSPointerUp", touchHandler, false);

 

Once the player fires off the event I call a custom touchHandler function like so:

 //Verify if point was within the bounds of an actual ship
 function touchHandler(event) {
     for (var i = 0; i < MAX_SHIPS; i++) {
         var ship = ships[i];
         if (shipHit(ship.x, ship.y, event.x, event.y)) {
             ships[i] = destroyShip(ship);
         }
     }
 }

This function loops through all of the Ship objects I have on screen and compares their current x and y coordinates to the x and y coordinates of the touch.  If it finds that the touch was inside the bounds of a ship it marks that ship for destruction.  The destroyShip function runs through an animation of the ship blowing up over a pre-determined amount of frames (currently 12).

If you are curious about what each of these Ship objects look like here is the function I created to track all of their state:

 function Ship(MAX_X, MAX_Y, MIN_ACCEL, MAX_ACCEL, LVL_MULTIPLY) {
  
     this.x = Math.random() * MAX_X;
     this.y = Math.random() * MAX_Y;
  
     var speed = randomRanged(MIN_ACCEL, MAX_ACCEL);
     var extra = speed * LVL_MULTIPLY;
  
     this.accel = speed + extra;
     this.img = new Image(); 
     this.img.src = randomImg();
     this.destroyed = false;
     this.destroyRendered = 0;
 };
  
 function randomRanged(a, b) {
     return (Math.floor(Math.random() * (1 + b - a))) + a;
 }
  
 function randomImg() {
     var images = Array(3);
  
     //TODO: new ship artwork
     images[0] = "/images/ship.png";
     images[1] = "/images/ship1.png";
     images[2] = "/images/ship2.png";
     images[3] = "/images/ship3.png";
  
     var ran = randomRanged(0, 3);
  
     return images[ran];
 }

This is what the shipHit function looks like:

 //Verify pixels clicked by pointer are within bounds of a ship's drawn pixels
 function shipHit(shipX, shipY, x, y) {
     var maxX = shipX + SHIP_WIDTH;
     var maxY = shipY + SHIP_HEIGHT;
     if (x >= shipX && x <= maxX && shipX >= 0 && y >= shipY && y <= maxY) {
         return true;
     }
     else {
         return false;
     }
     
 }

Finally, here is the destroyShip function:

 function destroyShip(ship) {
  
     var r = randomAccel(0, 2);
     var laserSound = lasers[r];
     SoundJS.play(laserSound, SoundJS.INTERRUPT_ANY);
    
     //TODO: Animation Explosion and better sound
     var explosion = new Image();
     explosion.onload = function () {
         ctx.drawImage(explosion, ship.x, ship.y);
     }
     explosion.src = "/images/explosion.png";
     ship.img = explosion;
     ship.destroyed = true;
  
     updateScore(POINTS_SHIPHIT);
  
     return ship;
 }

 

That’s it! Whether a user is touching the screen with all ten fingers or simply clicking with a mouse all of these events are handled for me.  Of course using more fingers on screen will make the game easier so I may want to add a difficulty mode to the games options at some point.

 

Testing Touch on Non-Touch Devices

Now what if you don’t have a Touch Enabled device to test your app out on?  Thankfully Visual Studio 11 offers a robust Simulator that in addition to offering you the ability to run your app at different resolutions comes with some handy Touch emulation features.  Select Simulator as your Debug target from the menu and start debugging.

Simulator

 

Once you see your emulator running click on the Hand Icon on the top right.

 

TouchMode

Your mouse pointer will now turn into a targeting reticle that will pass Touch Events across instead of Mouse Clicks!

 

Ships

While it doesn’t give the ability currently to do Multiple Touch points it will be enough for you to test your Touch Event Handlers and verify your code is working.

 

Conclusion

I hope this post has given you an idea of how easy it is to include Touch in your Metro Style Apps using the MSPointer API’s

If you are currently working on a Windows 8 app and want to get into the Windows Store I would love to hear about it!  You may also want to check out my previous Windows 8 Metro Style Development Tips: