XNA: Gaming across many platforms and the cloud
I’ve been working with UK XNA MVP Charles Humphrey on project ZuneRay. ZuneRay is a raycasting engine built by Charles’ for the Zune HD using XNA 3.1. With Windows Phone 7 Series in the pipeline we used the Zune HD as a target test platform with the intention of porting it to WP7S once the tools became available. ZuneRay uses a classic approach to delivering a 3D experience without requiring 3D support – at the time we didn’t know if 3D support would be in the Windows Phone 7 Series XNA version – so it was a pleasant surprise to find 3D support in there, and very satisfying to see ZuneRay port to XNA 4.0 and the WP7S really easily.
Well the tools CTP is now available, so Charles and I have been working away on ZuneRay with excellent results. ZuneRay is an XNA 3.1 with Zune HD extensions project. You get a Windows version ‘for free’, and an Xbox version just required the additional of Gamepad support. Moving ZuneRay to WP7S required upgrading the project to XNA 4.0. There is no ‘wizard’ to do this, the best approach is to create a new XNA 4.0 game and then pull in all your existing code and content. There are some platform specific bits in the generated Game1.CS file that you want to ensure are retained – but coming from the Zune platform originally these already existed.
There are breaking changes between Xna 3.1 and Xna 4.0 – the main ones for ZuneRay being around storage API, change of screen resolution and the changes in SpriteBatch parameters – but none of these took long to sort out. Shawn Hargreaves pointed out that WP7S running at 800x480 has 25% more pixels to draw than the original Xbox – but less CPU/GPU power to do it. The WP7S has a dedicated hardware scaler which means you can render your game at lower resolutions – like 600x360 56% of pixel data - and have the device scale it to fill the screen. While developing in the emulator this scaling functionality isn’t available, but then as the emulator is just that – not a simulator – your game takes advantage of the underlying PC hardware performance.
Project ZuneRay
Now I have the game running across Windows, Xbox, Windows Phone 7 Series and Zune HD – I wanted to integrate the cloud. My idea for demonstration purposes was really simple. Capture a camera image, publish it to the cloud and then have ZuneRay games acquire the image and use it in game as a wall texture.
Storing my image in the cloud is very simple – the image copy to Windows Azure Blob storage just uses the code I posted a while back. To capture the web cam I used a WPF application by Geert van Horrik – all I had to add was the resizing of the image to fit with the game requirements before sending it to Azure blob storage.
To retrieve the image from the blob store proved to be the tricky part. Although XNA is hugely consistent across the platforms the networking support varies enormously. The Zune has no programmatic network support. The Xbox only has networking to the Xbox Live services. Windows Phone 7 Series has a good sprinkling of support in various areas and Windows of course has the lot.
Looking at Windows Phone I was able to use the following code to simple make a webrequest using a known URL to the current image file.
- private void GetTextureFromAzure()
- {
- HttpWebRequest request;
- HttpWebResponse response = null;
- try
- {
- request = (HttpWebRequest)WebRequest.Create(new Uri(@"https://xxxx.blob.core.windows.net/publicfiles/dynamic.png"));
- response = (HttpWebResponse)request.BeginGetResponse(new AsyncCallback(RespCallback), request);
- }
- catch { }
- }
The callback function then uses Texture2D.FromStream to create a new texture from the response stream.
- private void RespCallback(IAsyncResult asynchronousResult)
- {
- try
- {
- HttpWebRequest myRequestState = (HttpWebRequest)asynchronousResult.AsyncState;
- HttpWebResponse response = (HttpWebResponse)myRequestState.EndGetResponse(asynchronousResult);
- Stream s = response.GetResponseStream();
- map.Textures[5] = Texture2D.FromStream(GraphicsDevice, s);
- s.Close();
- response.Close();
- }
- catch (System.Net.WebException)
- {
- //if (response != null)
- // response.Close();
- }
- }
The maps.texture array contains the textures presented as walls and objects in the game. By directly replacing the texture[5] only certain walls in the game levels present the web cam image, as can be seen below.
I use a count down timer to poll for a new image every minute for the purposes of this demo. I want to upgrade this poll mechanism with a push notification using the new Push Notification service for WP7S. In this way, the web cam application will be able to publish an image and then notify WP7S phones running the game of a new game texture. The games can then go and retrieve the image based on user preference for data service usage.
Charles and I intend to share more of Project ZuneRay’s code shortly.