Exploring the TouchPanel API with the Zune HD & XNA 3.1
While I have been fully enjoying my Zune HD experience I decided I should give apps a try after seeing the announcement about XNA Studio 3.1 and the XNA Extensions for the Zune HD. I have explored XNA a little prior to this but did not really dig into it. With my Zune HD in hand I decided it was time to take it for a spin.
Getting Started – What you need:
- Zune HD (16 or 32gb, I rock with the 32) + Cable
- Visual Studio 2008 / Visual C# + XNA Studio 3.1
- Zune HD Extensions
- Zune Software must be closed while running XNA Studio and debugging on your Zune hardware
Should you try to run software on your Zune without the extensions you will get an error message to the effect of “The XNA Framework runtime required by this game project is not available on ‘{YOUR ZUNE NAME HERE}’”. If you see this message, make sure you have the extensions installed and that your project targets XNA 3.1. This post on the XNA Creators Club forums helped me get started.
For some other background reading check out “Nazeeh’s Little Corner of the Web”, particularly his posts Anatomy of a Game Part 1 and “Hello World!” in XNA.
Exploring Microsoft.Xna.Framework.Input
As with all things framework, namespaces help us find things. The default XNA Project for the Zune does not give you too many pointers on where to find your input devices so I hopped over to object browser and found some interesting classes:
The documentation on the classes is pretty skim so I took a stab at some code and hacked this out:
protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); //Get the touches from the TouchPanel TouchCollection touches = TouchPanel.GetState(); if (TouchPanel.GetCapabilities().HasPressure) { foreach (TouchLocation item in touches) { squareManVector = item.Position; touchPressure = item.Pressure; } } base.Update(gameTime); }
There is a TouchCollectionEnumerator, however, I was looking for the simplest thing that could possibly work and this does the job. What I did was created a TouchCollection variable “touches” and call “GetState” on the TouchPanel class. That provides a TouchCollection which we can enumerate through to update the position and pressure. I’m not entirely sure the check for HasPressure is needed, but I was exploring the API and thought I would see what that provided.
A couple of variables in here may leave you wondering, so I will explain them real quick. squareManVector is a Vector2 which sets the position of my square man sprite:
who is aptly named squareManTexture. Yes I know, he is nothing fancy! In my first attempts just to learn I was looking for the basics, so I stuck him at a vector of 0,0. But, after discovering the touch API I decided to see if I could move him around.
Also note that for the Zune HD the “BackButton” is the button on the center of the device near the bottom. Based on the code above it becomes the de-facto exit button.
In the Draw method I have the following code:
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); string currentVector = string.Format("{0}.{1} : {2}", squareManVector.X.ToString(), squareManVector.Y.ToString(), touchPressure.ToString()); spriteBatch.DrawString(font, currentVector, new Vector2(50, 50), Color.Black); spriteBatch.Draw(squareManTexture, squareManVector, Color.White); spriteBatch.End(); base.Draw(gameTime); }
What is the end result you ask? When the game loads, squareMan is hanging out at the top left of the screen:
If you touch the screen he obediently moves:
But we can do more than touch…so let’s drag him around:
Note that while dragging the pressure sensitivity begins to display. Freaking sweet! I don’t think I have been this giddy about programming since I first started. Look forward to more articles on XNA programming as I dive into it with the Zune HD. I might even have to hook up my 360 with XNA Studio to give that a whirl!
Update 9/19/2009 @ 11:47PM CST
Because I’m still tinkering with it, here is how you can use an IEnumerator with the TouchPanel which is probably the more proper way to use it:
protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); IEnumerator<TouchLocation> touches = TouchPanel.GetState().GetEnumerator(); while (touches.MoveNext()) { squareManVector = touches.Current.Position; touchPressure = touches.Current.Pressure; } base.Update(gameTime); }
Enjoy!!
Comments are closed.



February 24, 2010 - 6:53 pm
Hi, sorry for this really really basic question but just started learning XNA for zune coming from an AS3 background.
In your example what type of variable did you set “touchPressure” to be. I tried “float” but it seems to act a bit crazy.
thanks for sharing!
josh
February 25, 2010 - 7:07 am
Sorry I didn’t include that. touchPressure was defined as a float at the class level in a private field.
How is it acting crazy?
February 25, 2010 - 8:46 am
This lesson actually started out by me following one of the lessons from this book http://www.amazon.com/Zune-Development-using-Experts-Voice/dp/1430218614/ref=sr_1_2?ie=UTF8&s=books&qid=1267108720&sr=1-2-spell however when I was done programming it I had realized that it was actually for the zune model prior to the HD and was designed for the TouchPad. Luckily I found your site! Your code pretty much had all I needed to upgrade the code from TouchPad to TouchScreen however…
It dosen’t seems to really follow my touch all that precisely to the point that it almost seems like a random movement when i touch. The Numbers in the string do seem to look accurate. And there are times it dashes about a pixel or so back and forth without me touching at all.
Heres my code:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace ZunePadExample
{
///
/// This is the main type for your game
///
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D characterTex;
SpriteFont aldoFont;
Vector2 characterPosition = new Vector2(120, 160);
Vector2 characterTexVector;
float touchPressure;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = “Content”;
// Frame rate is 30 fps by default for Zune.
TargetElapsedTime = TimeSpan.FromSeconds(1 / 30.0);
}
///
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
///
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
///
/// LoadContent will be called once per game and is the place to load
/// all of your content.
///
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
characterTex = Content.Load(“character”);
aldoFont = Content.Load (“Aldo”);
}
///
/// UnloadContent will be called once per game and is the place to unload
/// all content.
///
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
///
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
///
/// Provides a snapshot of timing values.
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
IEnumerator touches = TouchPanel.GetState().GetEnumerator();
while (touches.MoveNext())
{
characterTexVector = touches.Current.Position;
touchPressure = touches.Current.Pressure;
}
base.Update(gameTime);
}
///
/// This is called when the game should draw itself.
///
/// Provides a snapshot of timing values.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
string currentVector = string.Format(“{0}.{1} : {2}”, characterTexVector.X.ToString(), characterTexVector.Y.ToString(), touchPressure.ToString());
spriteBatch.DrawString(aldoFont, currentVector, new Vector2(50, 50), Color.Black);
spriteBatch.Draw(characterTex, characterTexVector, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
thanks for your assistance!
josh
February 28, 2010 - 12:39 pm
Update: Hey ya know what. This actually works fine, for some reason only when it was connected to the computer and in testing mode was it a lil wonky but if I run it from the disconnected zune it runs great.
thanks
josh
March 1, 2010 - 8:20 am
Ahhh, yes. It’s been a while but I remember the same thing happening. Much smoother without the debugger going.
When you click the menu button to exit does your Zune restart? That is the one thing I couldn’t figure out.
March 2, 2010 - 7:50 am
Yes apparently that is how Microsoft set it up
- “to clean up resources and reload the firmware so that no leaks or possible exploits exist”.
Obviously that is specific to non-Microsoft approved apps.
- josh
March 2, 2010 - 7:21 pm
Have you had a chance to play with the accelerometer at all?
March 3, 2010 - 11:32 am
Nope. It was on the list but got bumped way down to the bottom