Making the Zune HD Sparkle with XNA Game Studio 3.1 – Part 1
Introduction
This article explores using XNA Game Studio to access the two primary forms of user input on the Zune HD: the multitouch screen, and the accelerometer. We’ll do this by building a small demo that allows the user to create sparkles by touching the screen, and to move them around by tilting the device.
Over the course of this tutorial, the following subjects will be covered:
- Multitouch input
- Accelerometer input
- Animating blended sprites
- A simple UI (in part two)
I won’t be going over how to create a new XNA game project, nor will I describe how to add textures using the Content Pipeline. I assume that the reader has read enough about Game Studio to know how to do these things already. If you haven’t, I suggest downloading XNA Game Studio (a link is provided below) and going through the first tutorial provided in the Game Studio documentation.
The full sample, including source code, images, and VS2008 project files, can be downloaded here. Unless you want to make your own textures while following along with the tutorial, you’ll at least want to grab the images from the zip archive.
Prerequisites
This is a Zune HD tutorial: although some parts of the tutorial apply to all XNA Game Studio projects in general, much of the content here will apply only to devices that support both accelerometer and multi-touch input with XNA Game Studio 3.1. At the moment, that list begins and ends with the Zune HD. If you don’t already have a Zune HD, I’d recommend borrowing one from a friend, purchasing one, or sticking with Xbox 360 and Windows programming for now.
In addition to having access to a Zune HD, you’ll need the following software installed:
- Visual Studio 2008 – If you don’t already have Visual Studio 2008 Professional, you can download Visual Studio 2008 Express edition.
- XNA Game Studio 3.1 – Available from the Microsoft Download Center.
- XNA Game Studio 3.1 Zune Extensions – Also available from the Microsoft Download Center.
As I mentioned in the Introduction, you’ll also need an understanding of the basics of building an XNA Game Studio application.
First Steps
To begin, open Visual Studio 2008 and create a new XNA Game Studio project for Zune. Call it whatever you like. I called this project “InputToyZuneHD”.
Then, add some images to the project that we’ll be using. For now, all you’ll need is Flare.png, which contains the sparkle image. It looks like this:

Make sure the Asset Name in the Properties pane is “Flare” and the Build Action is ”Compile”. We’re now ready to add some code to the project!
Adding Sparkles
Open the file “Game1.cs” in your project, and right at the top of the Game1 class, add the following code:
public class Game1 : Microsoft.Xna.Framework.Game
{
static Random random = new Random();
class Sparkle
{
public Vector2 position;
public Vector2 speed;
public float rotation; // in radians
public Color color;
public long birthtime;
public Sparkle(float x, float y, long time)
{
position = new Vector2(x, y);
rotation = (float)(random.NextDouble() * 2.0 * Math.PI);
color = Color.White;
birthtime = time;
}
}
...
First, we’re just setting up the random number generator, which we’ll be using when setting up sparkle rotation. Then, we create a class to hold information about each sparkle: its position, speed, rotation, color (which will be used to fade the sparkles), and birthtime (also used for fading).
Then, we’ll create a constructor that takes a position in screen coordinates (x,y), and a birthtime. We’re using the same image for all of the sparkles, so there’s no need to save any image-specific data in the sparkle class.
Notice that we use a random rotation for each sparkle when it’s created. This helps, since we’re using the same image, from keeping every sparkle look exactly like the others when it appears. Random.NextDouble produces a number between zero and one, so by multiplying it by 2*PI, we can get a random rotation in radians.
Next, we define some constants that will be used to fade sparkles. We’ll define a maximum lifetime for each sparkle, the maximum number of sparkles allowed on the screen at once, an acceleration factor for sparkle movement, and a factor to control how quickly the sparkles will fade out.
Add this code beneath the definition of the Sparkle class:
const int SPARKLELIFE = 4000; // ticks
const int MAXSPARKLES = 100; // maximum number of sparkles, for performance tuning.
const float ACCELFACTOR = 0.01f;
const float FADEFACTOR = 255.0f / SPARKLELIFE;
We’ll now add a few variables to the class to hold the sparkle data. In Game1‘s class data section, where the graphics and spriteBatch members are declared, add new data members called flareImage, flareOffset, and sparkles, as shown:
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D flareImage;
Vector2 flareOffset;
List<Sparkle> sparkles;
Loading the Sparkle Image
There’s one last thing we’ll need to do before creating and drawing sparkles, and that’s loading the sparkle image into the Texture2D that we’ve declared for it.
In Game1.LoadContent, add lines to load the flare image and set the flare offset:
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
flareImage = this.Content.Load<Texture2D>("Flare");
flareOffset = new Vector2(
flareImage.Width * 0.5f, flareImage.Height * 0.5f);
The flareOffset will be used to rotate the sparkles, and is set to the middle of the sparkle texture.
Creating Sparkles with Touch
Now, let’s add some code that uses touch to create sparkles. We’ll allow the user to touch the screen to create a sparkle, or to create many sparkles by touching multiple points at the same time or by dragging a touch-point.
All of the code in this section will go into Game1.Update.
First, we’ll get the total game time as a long. The GameTime structure that’s passed to Update contains a number of members for different timing purposes. Since the sparkle birth-time is something that we’ll be tracking starting from the beginning of app launch, we’ll use the TotalGameTime member to get a timestamp for sparkle creation. This will allow us to fade the sparkles out over time, and to remove them from the list once they’ve faded.
To add a sparkle to a location touched on the screen, we’ll get the TouchCollection that contains all of the touch points (represented by the TouchLocation structure) that are active (either Pressed or Moved) this frame. Iterating through the list and adding sparkes at the TouchLocation.Position points is simple, as shown in the following code:
Add the following code to Update:
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
this.Exit();
}
long ttms = (long)gameTime.TotalGameTime.TotalMilliseconds;
// Process touch events
TouchCollection touchCollection = TouchPanel.GetState();
foreach (TouchLocation tl in touchCollection)
{
// add sparkles based on the touch location
sparkles.Add(new Sparkle(tl.Position.X,
tl.Position.Y, ttms));
}
We call TouchPanel.GetState to get the TouchCollection, and then simply iterate through each TouchLocation, passing the X and Y locations and the timestamp to Sparkle‘s constructor to add a new sparkle to the list.
We now have the code to add sparkles, but there’s still a problem that we need to solve: if you simply continue to add sparkles, you’ll soon have many thousands of sparkles on the list, which could really drag down your framerate.
To keep the frame-rate up, we should limit the number of objects that are being updated and drawn each frame. We’ll impose a limit, represented by MAXSPARKLES, on the number of sparkles that can be in the list at once, by removing sparkles from the beginning of the list if there are too many sparkles in existence. Right after adding a new sparkle, add code to remove the sparkles:
foreach (TouchLocation tl in touchCollection)
{
// add sparkles based on the touch location
sparkles.Add(new Sparkle(tl.Position.X,
tl.Position.Y, ttms));
// if there are too many sparkles, remove from the head.
if (sparkles.Count > MAXSPARKLES)
{
sparkles.RemoveAt(0);
}
}
Note: The sparkles are removed from the front of the list since these are the oldest sparkles: new sparkles are always added at the end. It would be quite unexpected (in other words, it would seem like a bug) from the user’s point-of-view if just-created sparkles suddenly disappeared!
Drawing the Sparkles
We now have the ability to add sparkles to our world, but unless we draw them on the screen, nobody (but you) will know they exist!
Drawing the sparkles on the screen is a simple matter of iterating through the list we’ve created, and drawing the Flare image at the location of each sparkle. In Game1.Draw, add the following code:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
// draw the sparkles
foreach(Sparkle s in sparkles)
{
// when drawing with a specified origin, the origin affects
// both the rotation and position parameters.
spriteBatch.Draw(
flareImage, s.position, null, s.color, s.rotation,
flareOffset, 1.0f, SpriteEffects.None, 0);
}
spriteBatch.End();
...
There are a number of SpriteBatch.Draw overloads provided in Game Studio, but we’ll use the version shown above since we’ll eventually want to change the color and rotation of each sparkle. For now, the color will always be Color.White and the rotation will always be zero.
The default template code for an XNA Game Studio game clears the screen to Color.CornflowerBlue. While this is a good color to use for debugging purposes, I’ve designed the sparkle image to look best on a black background. The clear color was changed to Color.Black to complement this.
If you’d like, compile and run the application on your Zune HD. You should be able to draw sparkles on the screen with your fingertips, and watch them disappear as you pass the MAXSPARKLES threshhold.
Fading the Sparkles
Although the above code removes sparkles from the list if there are too many, it’s likely that the user will notice sparkles suddenly vanishing from the display. It’s much nicer if we fade them out, so the user feels that the eventual dissapearance of the sparkle is natural within the design of the world we’re creating.
To do this, we’ll make use of the sparkle’s timestamp, comparing it to the current timestamp to fade the sparkle depending on its age. We’ll place this code directly after the code, entered in the previous section, that creates the sparkles in the Update method.
// update the sparkles. We count from the end of the list in case
// we need to remove a sparkle (without upsetting the order).
for (int i = sparkles.Count - 1; i >= 0; i--)
{
Sparkle s = sparkles[i];
if ((ttms - s.birthtime) > SPARKLELIFE)
{
sparkles.RemoveAt(i);
continue;
}
else
{
// fade the sparkle a bit, depending on its age.
s.color.A = (byte)(255.0f - (ttms - s.birthtime) * FADEFACTOR);
}
}
If the sparkle has passed the end of its lifetime, it’s removed from the list.
Rebuild and deploy your updated application. You should now see the sparkles fading!
Adding Motion with the Accelerometer
We’ll now use the Zune HD’s accelerometer to move the sparkles around on the screen, and add a little speed-based rotation to the sparkles to make them more interesting.
To do this, directly after the total game time calculation, get the elapsed game time in milliseconds, and then get the accelerometer state as shown:
long ttms = (long)gameTime.TotalGameTime.TotalMilliseconds; // elapsed time will be used in updating movement float etms = gameTime.ElapsedGameTime.Milliseconds; // grab the accelerometer state. This will be used for sparkle // movement. AccelerometerState accelState = Accelerometer.GetState();
The elapsed game time will be used during sparkle movement. Since I’m only interested in the elapsed time since the last frame, and I’m not ever expecting this to be more than a second, I use only ElapsedGameTime.Milliseconds.
Next, inside the loop used to update the sparkles, right below the code to fade the sparkles, add the following lines:
// fade the sparkle a bit, depending on its age.
s.color.A = (byte)(255.0f - (ttms - s.birthtime) * FADEFACTOR);
// accelerate the sparkle depending on accelerometer action.
s.speed.X += accelState.Acceleration.X * ACCELFACTOR;
s.speed.Y += -accelState.Acceleration.Y * ACCELFACTOR;
// move the sparkle based on its speed.
s.position.X += s.speed.X * etms;
s.position.Y += s.speed.Y * etms;
s.rotation += s.speed.Length() * ACCELFACTOR * etms;
We’re adding speed to each sparkle based on the current state of the accelerometer, and then updating its position based on its speed. Additionally, we’re adding a bit of rotation depending on the magnitude of the resulting speed vector. As simple as it is, the effect looks fairly nice.
No changes are needed to the drawing code. Once you rebuild and deploy, you should now see the sparkles moving as you tilt the device.
What’s Next?
The Sparkle application is fairly complete, but for a user who doesn’t know how it works, it might seem a bit mystifying: unless you touch the screen once it starts, you only see a black screen.
It would be nice to have some instructions pop up as the application starts, and perhaps a way to “freeze” the sparkle fading so that the user has more time to play with the sparkles as they slide around the screen.
In the next part of the tutorial, I’ll add a GUI that consists of an instructions screen and a menu that appears at the bottom of the screen.
Continue with: Making the Zune HD Sparkle with XNA Game Studio 3.1 – Part 2
Tags: accelerometer, input, touch, XNA Game Studio Docs & Resources, Zune HD