Tuesday, July 27, 2010

[XNA] Multi-touch input on Windows Phone emulator with just a mouse

The recent release of Windows Phone Developer Tools Beta added some great multi-touch functionality and gesture support using Game Studio 4.0 for Windows Phone. Unfortunately for those of us without a phone or a touch screen monitor, testing multi-touch gestures such as pinch and zoom are not supported by the emulator using just a mouse.

However, thanks to the wonderful gestures API, one can create a pinch/zoom interpreter with relative ease.  Below are some XNA game projects with such an interpreter. Feel free to reuse and recycle!

Samples
This first project contains a gesture interpreter that uses a moveable blob to represent an extra finger on the screen.  Place a blob by holding the "n" key on your keyboard and left clicking on the screen in the emulator*.  Then using your mouse, you can simulate pinches and zooms relative to the blob.

*Note: You may have to switch the phone emulator input from the virtual keyboard to your hardware keyboard by hitting the "Pause/Break" key.


This second project shows how to import the interpreter into an existing application, namely the gestures sample from the XNA developer education catalog.


How it works
The interpreter sits between your Game and the TouchPanel.  It reads in all gestures each update and populates its own queue of GestureSamples.  The simulator is modeled after the TouchPanel so code changes to your Game class are minimal.

The MultitouchSimulator constructor requires the gestures you want enabled for your game and an asset to draw for blobs. Enable gestures first, pass them to the simulator in the constructor, and add the simulator as a game component.

private MultitouchSimulator mtSimulator;

public Game() {
    graphics = new GraphicsDeviceManager(this);
    Content.RootDirectory = "Content";

    // Frame rate is 30 fps by default for Windows Phone.
    TargetElapsedTime = TimeSpan.FromTicks(333333);

    // Enable Gestures
    TouchPanel.EnabledGestures = GestureType.Pinch | GestureType.Tap | GestureType.FreeDrag;

    // Add simulator to game components
    mtSimulator = new MultitouchSimulator(this, "blob", TouchPanel.EnabledGestures);
    this.Components.Add(mtSimulator);            
}

Then instead of looping through the touch panel's GestureSamples in your update method, loop through the MultitouchSimulator's GestureSamples.

while (TouchPanel.IsGestureAvailable)
{
    GestureSample gesture = TouchPanel.ReadGesture();

    switch (gesture.GestureType)
    {
        // TODO: handle the gestures
    }
}
becomes...
while (mtSimulator.IsGestureAvailable)
{
    GestureSample gesture = mtSimulator.ReadGesture();

    switch (gesture.GestureType)
    {
        // TODO: handle the gestures
    }
}

That's it, minimal code changes so you can get to testing your multitouch gestures quickly and when it's time to release (or hopefully test on a real device) you can pop out the component and go.