Monogame in Windows Phone 8


Windows phone offers a great platform for game developers to develop games for the mobile device. With the introduction of Windows Phone 7 developers had the option of creating games for windows phone in XNA 4.0 and DirectX. However XNA is no longer natively supported in Windows Phone 8 (XNA games still work on Windows Phone 8 but they work in a “compatibility mode”) and one is limited to usage of XAML with Direct3D technology to create games. The Direct3D component requires one to write code in C++ which in today’s modern world may not be a first choice for developers, at least for the native application programmers. So one has to either learn C++ to start using Direct3D and even though he does learn C++ he has to still learn Direct3D (assuming he is not familiar with Direct3D). The solution to the above problem lies in Monogame.

A first you might say, I need to learn another technology. But it’s not a new technology but just old things packaged into a new one. Monogame has already been available into other platforms like Android and iOS. Monogame inherently uses the Microsoft XNA 4 Application Programming Interface and also has the same Content Management Pipeline. For graphics rendering Monogame 3.0 uses OpenGL 2 shaders. Monogame also uses the SharpDX libraries to expose and utilize the full DirectX capabilities.

Monogame is an open source project and is available at GitHub at the following location https://github.com/mono/MonoGame. The installer for Visual Studio 2010/2012 is available at http://monogame.codeplex.com/releases/view/102870.

We shall now see how to create games using Monogame.

Creating your first Monogame Project:

After you have installed Monogame 3.0 start Visual Studio 2012 and then create a New Project. Creating a new project gives you the following window as shown in Figure 1.

If you have installed Monogame successfully then you can see Monogame in the left Navigation below Visual C#. If you click on the Monogame link you will see the various Visual Studio Templates that Monogame comes with. We will be using the first one in the list, i.e. Monogame Windows Phone 8 Project.

Create the project with name “BallBalancer”. This application will have a ball placed on your phone screen and it will roll over in the direction you tilt your phone.

After creating the project we would get a set of files generated by the Monogame template as shown in the Figure 2.

You will see that apart from the regular Windows Phone 8 project files created for a XAML project and addition file named Game1.cs is created. This file is the one that is similar to the XNA Game file. Let’s rename it to BallBalancerGame.cs.

Open the BallBalancerGame.cs file and you will see that it has 5 overridden methods apart from the constructor. If you by now realize it is the same game file that you generate in XNA games.

Next, let’s create a new solution folder and name it “Content”.

This folder will contain the XNA objects that we will use in our games, in our case we will add a pre-compiled ball graphics.

Note: Currently the Monogame project does not support the Content Processing features provided by XNA 4.0 project and hence we will have to compile our game resources in XNA and then add them into our project.

In our case we have an already compiled Ball graphics added to the project as shown below in Figure 3.

We will now create a class for handling the Ball data. Let’s create a new class and name it GameBall.cs as shown in Figure 3. The code for GameBall.cs is contained in Figure 4. The GameBall class contains two variables Position and Texture where Position holds the current position of the Ball and the Texture variable holds the graphics part of it. We also create a bounding rectangle using the Texture variable to check for collisions, rest of the methods are self-explanatory.

public class GameBall {
 private Vector2 _position;
 private Texture2D _texture;

public Vector2 Position
 {
 get { return _position; }
 set { _position = value; }
 }

public Texture2D Texture
 {
 get { return _texture; }
 set { _texture = value; }
 }

// Bounds of the ball, currently approximated to a rectangle
 public Rectangle Bound
 {
 get
 {
 return new Rectangle((int)_position.X + 5, (int)_position.Y + 5, _texture.Width - 5, _texture.Height - 5);
 }
 }

//Change the position of the ball by 'p' value
 public virtual void Move(Vector2 p)
 {
 _position += p;
 }

//Draws the Ball in every update
 public virtual void Draw(SpriteBatch _spriteBatch)
 {
 _spriteBatch.Draw(_texture, Position, Color.White);
 }

//Check collision with phone boundary walls
 internal void CheckCollision()
 {
 if (Position.X < 0)
 Position = new Vector2(0, this.Position.Y);
 if (Position.X + Texture.Width > BallBalancerGame.SCREEN_WIDTH)
 Position = new Vector2((float)(BallBalancerGame.SCREEN_WIDTH - Texture.Width), this.Position.Y);

if (Position.Y < 0)
 Position = new Vector2(this.Position.X, 0);
 if (Position.Y + Texture.Height > BallBalancerGame.SCREEN_HEIGHT)
 Position = new Vector2(this.Position.X, (float)(BallBalancerGame.SCREEN_HEIGHT - Texture.Height));
 }
 }
 

Now let’s add some game logic to the BallBalancerGame.cs file. In this class add the following variables, where SCREEN_HEIGHT and SCREEN_WIDTH are the height and width of the screen which we will set in the “Initialize” method. The variable ACCELERATION stores the speed at which the ball will move in the game. _motion is variable to the windows phone 8 Motion sensor API.

private SpriteBatch _spriteBatch;
private Motion motion;
private GameBall _gameBall;
public static double SCREEN_HEIGHT;
public static double SCREEN_WIDTH;
private const float ACCELERATION = 20;

After we have declared the variable lets add the following code into the “Initialize()” function. This code first sets the screen height and width based on the graphics device, then it tries to check if the device supports motion sensor using the Motion Sensor API found in Microsoft.Devices.Sensors namespace. If the device supports the Motion sensors then we will initialize it with an update interval set to 20 milliseconds and start the Motion API.

 SCREEN_HEIGHT = GraphicsDevice.Viewport.Height;
 SCREEN_WIDTH = GraphicsDevice.Viewport.Width;

_gameBall = new GameBall();

if (!Motion.IsSupported)
 {
 MessageBox.Show("This device doies not support the Motion API.");
 return;
 }

if (motion == null)
 {
 motion = new Motion();
 motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(200);
 }

// Try to start the Motion API.
 try
 {
 motion.Start();
 }
 catch (Exception ex)
 {
 MessageBox.Show("The Motion API could not be started.");
 }
 

In the “LoadContent()” method we will load the texture for the Game Ball from the xnb file as shown below.

_gameBall.Texture = Content.Load<Texture2D>("blue_circle_small");

In the “Update()” method we will add the ball motion code. We take the Roll and the Pitch values from the motion sensor API and accordingly update the position of the game ball.

 if (motion.IsDataValid)
 {
 float x = motion.CurrentValue.Attitude.Roll;
 _gameBall.Move(new Vector2((float)(x * ACCELERATION), 0));

float y = motion.CurrentValue.Attitude.Pitch;
 _gameBall.Move(new Vector2(0, (float)(y * ACCELERATION)));

_gameBall.CheckCollision();
 }

And finally we will re-draw the game ball in the “Draw()” method as below.

_gameBall.Draw(_spriteBatch);

After we have followed the above steps the BallBalancerGame.cs file should look like the class shown below.

 /// <summary>
 /// This is the main type for your game
 /// </summary>
 public class BallBalancerGame : Game
 {
 private GraphicsDeviceManager _graphics;
 private SpriteBatch _spriteBatch;
 private Motion motion;
 private GameBall _gameBall;

public static double SCREEN_HEIGHT;
 public static double SCREEN_WIDTH;
 private const float ACCELERATION = 20;

public BallBalancerGame()
 {
 _graphics = new GraphicsDeviceManager(this);
 Content.RootDirectory = "Content";
 }

/// <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
 SCREEN_HEIGHT = GraphicsDevice.Viewport.Height;
 SCREEN_WIDTH = GraphicsDevice.Viewport.Width;

_gameBall = new GameBall();

if (!Motion.IsSupported)
 {
 MessageBox.Show("This device doies not support the Motion API.");
 return;
 }

if (motion == null)
 {
 motion = new Motion();
 motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(200);
 }

// Try to start the Motion API.
 try
 {
 motion.Start();
 }
 catch (Exception ex)
 {
 MessageBox.Show("The Motion API could not be started.");
 }

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);
 _gameBall.Texture = Content.Load<Texture2D>("blue_circle_small");
 // TODO: use this.Content to load your game content here
 }

/// <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)
 {
 // TODO: Add your update logic here
 if (motion.IsDataValid)
 {
 float x = motion.CurrentValue.Attitude.Roll;
 _gameBall.Move(new Vector2((float)(x * ACCELERATION), 0));

float y = motion.CurrentValue.Attitude.Pitch;
 _gameBall.Move(new Vector2(0, (float)(y * ACCELERATION)));

_gameBall.CheckCollision();
 }
 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);
 _spriteBatch.Begin();
 _gameBall.Draw(_spriteBatch);
 // TODO: Add your drawing code here
 _spriteBatch.End();
 base.Draw(gameTime);
 }
 }

Lots of coding, huff, now let’s build the project and make sure there are no build errors. If there are no errors then let’s run the project on windows phone 8 device that supports Motion Sensor.

Figure 11

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s