Porting Sparkles from Zune HD to Windows Phone 7

InputToy (also known as “Sparkles”) started as an application designed to demonstrate programming touch and accelerometer input on the Zune HD with XNA Game Studio 3.1. However, when the XNA Game Studio 4 Community Technical Preview (CTP) was released with support for the upcoming Windows Phone 7, including a built-in emulator, I felt that porting the application to Windows Phone was the next logical step.

This tutorial will provide step-by-step instructions on porting an application from the Zune HD to Windows Phone, using the existing Zune HD Sparkles application (InputToyZuneHD) as an example.  The full source code for that version can be downloaded here.

Important Notes:

  • This article is written about pre-released technology.  It is likely that some of the features, the API, and the products mentioned here will change before final release.  I will attempt to keep this article up-to-date, but no guarantees can be made of the accuracy of this material when compared to the final (future) product.
  • Since the Windows Phone emulator doesn’t include accelerometer support, you’ll need to wait for actual Windows Phone 7 devices to become available to actually see that part of the code in action, but you can certainly work with touch input right now using the emulator.

Prerequisites

This tutorial assumes that you’ve already created an application for Zune HD using the steps in the first set of tutorials. If you haven’t, you may want to at least read through Making the Zune HD Sparkle with XNA Game Studio 3.1 – Part 1 and Part 2.

Before you begin, you’ll also need the following:

For reference, the full source code for the finished application for Windows Phone 7 can be downloaded here.

Converting a Zune HD project to Windows Phone 7

The first thing you’ll need to do is create a new Windows Phone game project and copy the source files into it. Call the project InputToyWP7. I won’t go into this process in detail here, since there’s already an article in the XNA Game Studio 4 documentation about how to do exactly that, called Migrating from Zune to Windows Phone.  It’s a great guide—trust me, I wrote it!

The source files you will need to copy from the old project are:

  • Game1.cs
  • Instructions.cs
  • Menu.cs

Copy these into the InputToyWP7 directory in your Visual Studio 2010 project.

You’ll also notice that there’s an InputToyWP7Content directory in your project, as well. A major difference between the way XNA Game Studio 3.1 and 4.0 behave is that content projects are now full projects alongside the code project, and not in a sub-directory within the code project’s directory.

From the old project’s Content directory, copy the following files into the new project’s InputToyWP7Content directory:

  • btnHelp.png
  • btnPause.png
  • btnPlay.png
  • Flare.png
  • Instructions.png

Once all these files have been added to your projects, you’ll be ready to proceed with the code modification necessary to get the application running on the WP7 emulator supplied with the XNA GS 4 CTP (wow, three TLAs in a row!).

Modifying the game code for Windows Phone

Screen dimensions

The original Zune HD version of this application was written for the Zune HD’s native screen resolution of 272 x 480.  Windows Phone 7, however, sports a native resolution of 480 x 800.  At some point, the Windows Phone emulator may support the built-in hardware scaling that is planned for the phone, but for now, it supports only the standard 480 x 800 resolution.

In anticipation of being able to set my screen dimensions to be equal to the Zune HD’s resolution—therefore preserving the original look of my application—I’m going to set the screen dimensions in a Vector2 that I can easily change in the future.  Add the following member to the Game1 class:

Vector2 screenDimensions = new Vector2(480, 800);

Now, in the game’s constructor, we’ll set the GraphicsDeviceManager‘s PreferredBackBufferWidth and PreferredBackBufferHeight to these dimensions.  We’ll also set IsFullScreen to true.  Add the following code to Game1′s constructor:

// Frame rate is 30 fps by default for Windows Phone.
TargetElapsedTime = TimeSpan.FromSeconds(1/30.0);

// This makes use of the built-in hardware scaler to work with our original (Zune HD) resolution
graphics.PreferredBackBufferWidth = (int)screenDimensions.X;
graphics.PreferredBackBufferHeight = (int)screenDimensions.Y;

// use the whole screen
graphics.IsFullScreen = true;

Another neat thing that we’ll get for free is an automatic translation of touchscreen coordinates from WP7′s native resolution to the resolution that we set for the backbuffer, so we can count on having the same touch coordinates (272 x 480) that we did for Zune HD. This isn’t an issue now, since we’re using 480 x 800 resolution, but it’s nice to know that no additional code changes will be needed when using automatic backbuffer scaling.

Speaking of touch input… we’ll now modify our touch input code so it works with GS4.  Thankfully, there won’t be much to do.

Changing the touch input code for XNA Game Studio 4

One difference between XNA GS 3.1 and 4.0 is how the touch input classes are referenced.  In XNA GS 4, they are now inside their own assembly.  To make our old code work with XNA GS 4, we’ll need to add a new reference to Microsoft.Xna.Framework.Input.Touch to the top of Game1.cs:

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.Input.Touch;
using Microsoft.Xna.Framework.Media;

You’ll also need to make sure that Microsoft.Xna.Framework.Input.Touch is also referenced by your project itself:  Click on the References node in your InputToy source project, and make sure it contains Microsoft.Xna.Framework.Input.Touch in the list.  If it doesn’t, right click the References node and click Add Reference…, then select it from the list and click OK to add it to your project.

That’s it!  Aside from this change, we don’t need to do anything extra to our code to support touch input on WP7.  As mentioned before, due to the magic of hardware scaling, all our touch input code from the Zune HD version of the application will continue to work fine.

Changing the accelerometer code for Windows Phone

This is where things get interesting.  Accelerometers are not supported by XNA GS 4, as they were for Zune HD on XNA GS 3.1.  To work with the accelerometer on Windows Phone, you need to add the Microsoft.Devices.Sensors assembly to the project, which is, thankfully, included with the XNA GS 4 CTP you downloaded as a prerequisite.  Add the following line to the using statements at the beginning of Game1.cs (I added it after the using Microsoft.Xna.Framework.Media line):

using Microsoft.Devices.Sensors;

You’ll also need to make sure that Microsoft.Devices.Sensors is also referenced by your project, as you did for Microsoft.Xna.Framework.Input.Touch.

Microsoft.Devices.Sensors is not an XNA GS assembly—it’s supplied by Silverlight—and doesn’t follow the usual programming patterns used with XNA Game Studio.  There’s no polling for input as there was with Accelerometer.GetState in GS 3.1.

Instead, we’ll be using the AccelerometerSensor class in Microsoft.Devices.Sensors.  We’ll also define an event handler that will be called when the ReadingChanged event is raised.

First, add the following members to the Game1 class:

...
List<Sparkle> sparkles;
Instructions instructions;
Menu menu;
bool accelActive = false;
AccelerometerSensor accelSensor;
Vector3 accelReading = new Vector3();

First, we have a boolean value that we’ll use to keep track of whether the accelerometer is active or not.  Next is a member to hold the AccelerometerSensor object, and finally is a Vector3 that we’ll use to hold the X, Y, and Z values returned by the accelerometer.

Next, we’ll add the following code to Game1′s constructor:

// This makes use of the built-in hardware scaler to work with our original (Zune HD) resolution
graphics.PreferredBackBufferWidth = (int)screenDimensions.X;
graphics.PreferredBackBufferHeight = (int)screenDimensions.Y;

// use the whole screen
graphics.IsFullScreen = true;

accelSensor = new AccelerometerSensor();

// Add the accelerometer event handler to the accelerometer sensor.
accelSensor.ReadingChanged +=
   new EventHandler<AccelerometerReadingAsyncEventArgs>(AccelerometerReadingChanged);

// Start the accelerometer
try
{
   accelSensor.Start();
   accelActive = true;
}
catch (AccelerometerStartFailedException e)
{
   // the accelerometer couldn't be started.  No fun!
   accelActive = false;
}

After creating an instance of the AccelerometerSensor, we add the event handler to handle the ReadingChanged event.  It will be called AccelerometerReadingChanged, and takes an AccelerometerReadingAsyncEventArgs argument. We’ll define this handler in a short while.

For now, notice that we also have to Start the accelerometer, and that this call can fail with an AccelerometerFailedException.  If it does, we simply set accelActive to false.

In this case, we’ll have the accelerometer active during the entire run of the program.  In your own games, you may want to turn off the accelerometer when its not being used.  This can improve performance, since there will be no need to receive or respond to ReadingChanged.

Instead, we’ll just turn off the accelerometer when the program shuts down.  Add the following lines to UnloadContent, which is called as the game is exiting:

protected override void UnloadContent()
{
   // Unload any non ContentManager content here
   // Stop the accelerometer if it's active.
   if (accelActive)
   {
      try
      {
         accelSensor.Stop();
      }
      catch (AccelerometerStopFailedException e)
      {
         // the accelerometer couldn't be stopped now.
      }
   }
}

Now, lets revisit the ReadingChanged event handler.  We called it AccelerometerReadingChanged, but didn’t actually define the method.  We’ll do so now.  Add the following method to the Game1 class:

public void AccelerometerReadingChanged(object sender, AccelerometerReadingAsyncEventArgs e)
{
   accelReading.X = (float)e.Value.Value.X;
   accelReading.Y = (float)e.Value.Value.Y;
   accelReading.Z = (float)e.Value.Value.Z;
}

There isn’t much to it: this method simply gets the X, Y, and Z values from the AccelerometerReadingAsyncEventArgs object, and saves them in the Vector3 that we defined earlier.

Now, all we need to do is make use of this data.  We actually had code that did this for our Zune HD version of the application, and we’ll reuse that code.

In Game1′s Update method, remove the lines that were used to get the accelerometer state, since these are no longer used.  Remove these lines:

// grab the accelerometer state.  This will be used for sparkle
// movement.
AccelerometerState accelState = Accelerometer.GetState();

Later in Update, there’s code that sets the particle speed based on the value in the accelState variable.  Find it, and modify the code (modified bits are in green, as usual) so that it looks like this:

if (accelActive)
{
   // accelerate the sparkle depending on accelerometer
   // action.
   s.speed.X += accelReading.X * ACCELFACTOR;
   s.speed.Y += -accelReading.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;
}

The only changes we had to make were to make use of the accelActive value that tells us the accelerometer has been made active (by calling Start), and switching out the accelState variable that we removed earlier with our accelReading class member.

That’s it!  Though modifying the accelerometer code was a little more work than it took to modify the touch code, it didn’t take much more than defining a single event handler and adding the code to instantiate, start, and stop the AccelerometerSensor.

You should now be able to build the application and, once you get your hands on a Windows Phone 7 device, be able to see it behave just like it did for Zune HD.  For now, however, you can at least play with the touch portions of the application in the Windows Phone 7 emulator:

As before, please let me know if you have any questions or comments regarding this tutorial, or if you’d like to see articles covering other subjects.  I hope you enjoyed it!

Leave a Reply

You must be logged in to post a comment.