Tutorials‎ > ‎

XNA on Windows Phone 7 - Web Service for Multiplayer Game

posted Dec 28, 2011, 4:25 AM by Reza Aggi Prasetyo   [ updated Aug 15, 2016, 11:40 PM by Surya Wang ]

XNA on Windows Phone 7

                Developing a game on Windows Phone 7 can be done easier by using XNA Game Studio. This requires XNA Game Studio 4.0 which released in September 2010.

                First, you need to download Windows Phone Developer Tools RTW here http://go.microsoft.com/fwlink/?LinkID=189554. It is the web installer version of Windows Phone Developer Tools RTW. It includes the following:

-          Visual Studio 2010 Express for Windows Phone

-          Windows Phone Emulator Resources

-          Silverlight 4 Tools For Visual Studio

-          XNA Game Studio 4.0

-          Microsoft Expression Blend for Windows Phone

However, installing it using web installer will require internet connection. This will trouble the one who gets it on low-bandwidth connection. I suggest you to download it in .ISO version here http://go.microsoft.com/fwlink/?LinkId=201927.

 

XNA Multiplayer Game on Windows Phone 7

                A mobile phone would lack of low latency or socket connections, so a multiplayer game on Windows Phone 7 would better if it’s a turn based game. The communications needed can be accomplished using a web service and http communications.

 

Creating a New XNA on Windows Phone 7 Project

1.       Open the Microsoft Visual Studio 2010 Express for Windows Phone. Select File --> New Project.


Select the Windows Phone Game (4.0) template. In the name field, set the name of your project. In the location field, set the path where you would like to save your project. After that, click OK button.

 

2.       After the project has been created, two basic projects will be created in the solution.


The <your project name> solution will contain your game algorithm, your game class, and program class (the same with usual XNA solution for PC or Xbox). The <your project name>Content solution will contain the contents of your game like images, sounds, etc.

 

Create a New WCF Project

1.       Open the Microsoft Visual Studio 2010. Select File --> New Project.


Select the WCF Service Application template under Visual C# à WCF. In the name field, set the name of your project. In the location field, set the path where you would like to save your project. After that, click OK button.

 

2.       Your solution explorer will be like this.


 

3.       Rename your service interface (IService1.cs) by using the “Rename” command on the “Refactor” menu.

 

Rename into IMyGameService.



 

Click the apply button.



 

Rename the IService1.cs file into IMyGameService.cs.


 

4.       Rename your service class (Service1.svc) by using the “Rename” command on the “Refactor” menu.


 

Rename into MyGameService.


 

Click the apply button.


 

Rename the Service1.svc file into MyGameService.svc.


 

 

Creating The Service Operations

1.       The Game Host Class

Add a new class named MyGame under MyGameServer solution.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

 

namespace MyGameServer

{

    public class MyGame

    {

        public Guid ID { set; get; }

        public string Host { set; get; }

        public string Client { set; get; }

        public string Status { set; get; }

        public List<int> Step;

        public string WhoMoveLast { set; get; }

 

        public MyGame()

        {

            ID = Guid.NewGuid();

            Status = "Waiting";

            Step = new List<int>();

            WhoMoveLast = "";

        }

 

        public void DoMove(int move)

        {

            Step.Add(move);

        }

 

        public int GetLastMove()

        {

            return Step.Last();

        }

    }

}


 

2.       Hold The MyGame Class

Because of we won’t use any databases for holding the hosted game data, we will use a static list to hold our MyGame class.

Add this code into MyGameService.svc.cs.

static List<MyGame> GameList = new List<MyGame>();

 

3.       HostGame

This operation will be used to host a new game (usually called a room) so that other user can join and play together. In order to create a new operation, open the IMyGameService.cs and add this code

[OperationContract]

string HostGame(string nickname);


 under

public interface IMyGameService
.

 

Then, open the MyGameService.svc.cs and add this code.

 

        public string HostGame(string nickname)

        {

            MyGame myGame = new MyGame();

            myGame.Host = nickname;

            GameList.Add(myGame);

 

            return myGame.ID.ToString();

        }


 

This operation will return the game ID that has been hosted.

 

4.       JoinGame

This operation will be used to join a hosted game. In order to create a new operation, open the IMyGameService.cs and add this code

[OperationContract]

string JoinGame(string GameID, string nickname);



 under

public interface IMyGameService

 

Then, open the MyGameService.svc.cs and add this code.

 public string JoinGame(string GameID, string nickname)

        {

            for (int i = 0; i < GameList.Count(); i++)

            {

                if (GameList[i].ID.ToString() == GameID)

                {

                    GameList[i].Client = nickname;

                    return GameList[i].Host;

                }

            }

            return null;

        }


 

This operation will return the nickname of player who hosted the game.

 

 

Add Service Reference to Your Game

If you have installed the latest version of Windows Developer Tools, it will be the same like other .NET applications in adding a service reference.

1.       Run your WCF application by pressing F5 while opening MyGameService.svc.cs in MyGameServer project.

 

2.       Here is the window of WCF Test Client if your service has been running.


 

3.       Look at the address where it’s hosted, we will use it later.


You could set a fixed address of the service in order not to change the service reference every time the service was re-run.

 

4.       Open your XNA Game application, right click on References, select Add Service Reference….


 

5.       Type your service address on the Address textfield, then press Go.


 

6.       Press OK.


A new service reference has been added to your project.

 

 

Call The Service

1.       Open your Game Class (Game1.cs). Add the service reference to your code.

using MultiplayerTurnBaseGame.ServiceReference1;

 

2.       Add this variable to your class.

SpriteFont spriteFont;

MyGameServiceClient sc;

string GameID;

string nickname = "MyHost";

string text = "";

 

We will use the SpriteFont to draw text of information in our program.

 

3.       Add this code to LoadContent() method.

sc = new MyGameServiceClient();

sc.HostGameCompleted += new EventHandler<HostGameCompletedEventArgs>(sc_HostGameCompleted);

 

4.       Create a new method called sc_HostGameCompleted to handle your service result.

  void sc_HostGameCompleted(object sender, HostGameCompletedEventArgs e)

        {

            if (e.Result != null)

            {

                GameID = e.Result;

                text = "A game has been hosted, name: " + GameID;

            }

            else

            {

                text = "Failed to host a game";

            }

        }

 

This method will handle the result of HostGame method in our server game service. We will only show the string result to the screen.

 

 

Show The Text

1.       Add a new item to MultiplayerTurnBaseGameContent project.


 

2.       Select Sprite Font, and then click Add.


 

3.       The you will find a new *.spritefont item in MultiplayerTurnBaseGameContent project.


 

4.       Change your Draw method to be like this.

 protected override void Draw(GameTime gameTime)

        {

            GraphicsDevice.Clear(Color.CornflowerBlue);

 

            // TODO: Add your drawing code here

            Vector2 textSize = spriteFont.MeasureString(text);

            Viewport viewport = this.GraphicsDevice.Viewport;

 

            Vector2 textPosition = new Vector2((viewport.Width - textSize.X) / 2, (viewport.Height - textSize.Y) / 2);

 

            spriteBatch.Begin();

            spriteBatch.DrawString(spriteFont, text, textPosition, Color.Black);

            spriteBatch.End();

 

            base.Draw(gameTime);

        }


 

 

Run The Game Application

1.       Just start debugging your MultiplayerTurnBaseGame project by pressing F5.

 

2.       After the service has return the result of HostGame method, your application screen will be like this.


 

 

Join The Game

1.       To test joining the game, you must create a new XNA on Windows Phone 7 application. Repeat the step of making MultiplayerTurnBaseGame, add the service reference, and add the sprite font file.

 

2.       After that, make your Game1.cs to be like this.

 

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.Input.Touch;

using Microsoft.Xna.Framework.Media;

using MultiplayerTurnBaseGameClient.ServiceReference1;

 

namespace MultiplayerTurnBaseGameClient

{

    /// <summary>

    /// This is the main type for your game

    /// </summary>

    public class Game1 : Microsoft.Xna.Framework.Game

    {

        GraphicsDeviceManager graphics;

        SpriteBatch spriteBatch;

        SpriteFont spriteFont;

        MyGameServiceClient sc;

        string Host;

        string nickname = "MyClient";

        string text = "";

 

        public Game1()

        {

            graphics = new GraphicsDeviceManager(this);

            Content.RootDirectory = "Content";

 

            // Frame rate is 30 fps by default for Windows Phone.

            TargetElapsedTime = TimeSpan.FromTicks(333333);

        }

 

        /// <summary>

        /// 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.

        /// </summary>

        protected override void Initialize()

        {

            // TODO: Add your initialization logic here

 

            base.Initialize();

        }

 

        /// <summary>

        /// LoadContent will be called once per game and is the place to load

        /// all of your content.

        /// </summary>

        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

            spriteFont = this.Content.Load<SpriteFont>("SpriteFont1");

 

            sc = new MyGameServiceClient();

            sc.JoinGameCompleted += new EventHandler<JoinGameCompletedEventArgs>(sc_JoinGameCompleted);

 

            //Call the service

            sc.JoinGameAsync("6a4b7706-25be-4a1a-a8ec-06ae95583a4a", nickname);

        }

 

        void sc_JoinGameCompleted(object sender, JoinGameCompletedEventArgs e)

        {

            //throw new NotImplementedException();

            if (e.Result != null)

            {

                Host = e.Result;

                text = "You have joined " + Host + " room";

            }

            else

            {

                text = "Failed to join a game";

            }

        }

 

        /// <summary>

        /// UnloadContent will be called once per game and is the place to unload

        /// all content.

        /// </summary>

        protected override void UnloadContent()

        {

            // TODO: Unload any non ContentManager content here

        }

 

        /// <summary>

        /// Allows the game to run logic such as updating the world,

        /// checking for collisions, gathering input, and playing audio.

        /// </summary>

        /// <param name="gameTime">Provides a snapshot of timing values.</param>

        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

 

            base.Update(gameTime);

        }

 

        /// <summary>

        /// This is called when the game should draw itself.

        /// </summary>

        /// <param name="gameTime">Provides a snapshot of timing values.</param>

        protected override void Draw(GameTime gameTime)

        {

            GraphicsDevice.Clear(Color.CornflowerBlue);

 

            // TODO: Add your drawing code here

            Vector2 textSize = spriteFont.MeasureString(text);

            Viewport viewport = this.GraphicsDevice.Viewport;

 

            Vector2 textPosition = new Vector2((viewport.Width - textSize.X) / 2, (viewport.Height - textSize.Y) / 2);

 

            spriteBatch.Begin();

            spriteBatch.DrawString(spriteFont, text, textPosition, Color.Black);

            spriteBatch.End();

 

            base.Draw(gameTime);

        }

    }

}

 

3.       You need to change the GameID parameter of JoinGame method to be the same with the GameID returned to the host.

//Call the service

sc.JoinGameAsync("<change to valid GameID>", nickname);

 

4.       Run your project and you application screen will be like this.