Monkey Tap
Creating MonkeyTap User Interface
Loading game assets is done through a ContentManager, which is exposed by default via the “Content” property of the Game class. First, let’s import some necessary namespaces and declare fields to store our game assets:
using System.Collections.Generic;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D monkey;
Texture2D background;
Texture2D logo;
SpriteFont font;
SoundEffect hit;
Song title;
}
Next, we need to load our assets. Add the following code to your LoadContent method, which is where all assets should be loaded in MonoGame:
monkey = Content.Load<Texture2D> ("monkey");
background = Content.Load<Texture2D> ("background");
logo = Content.Load<Texture2D> ("logo");
font = Content.Load<SpriteFont> ("font");
hit = Content.Load<SoundEffect> ("hit");
title = Content.Load<Song> ("title");
MediaPlayer.IsRepeating = true;
MediaPlayer.Play (title);
All of our content is now loaded, from textures to audio. Now that we have loaded our content, it’s time to draw the user interface on the screen. The SpriteBatch class is used to draw 2D images and text. To make rendering as efficient as possible, drawing is batched together and sprites must be drawn between the Begin and End methods of SpriteBatch. Update the Draw method to draw our monkey texture on the screen using the spriteBatch field we just created:
protected override void Draw (GameTime gameTime)
{
graphics.GraphicsDevice.Clear (Color.CornflowerBlue);
spriteBatch.Begin ();
spriteBatch.Draw (monkey, Vector2.Zero);
spriteBatch.End ();
base.Draw (gameTime);
}
Hit F5 or Cmd+Enter to run the application. You should see the monkey smiling with his banana and hear the music from Jason Farmer we set to play in LoadContent. Now that our game assets are loading, let’s build the rest of the user interface for playing MonkeyTap!
Building the MonkeyTap User Interface
Traditional Whack-a-Mole style games have moles that randomly appear on screen and must be tapped to disappear. Rather than randomly rendering monkeys on the screen, we can use a grid to help ensure that the monkeys don’t overlap to provide a consistent user experience. The grid is made up of multiple cells, each of which contains a rectangle, color, countdown timer, and transition value that will be used to fade the monkey in. Copy and paste the following GridCell class into the Game1.cs file:
public class GridCell
{
public Rectangle DisplayRectangle;
public Color Color;
public TimeSpan CountDown;
public float Transition;
public GridCell ()
{
Reset ();
}
public bool Update(GameTime gameTime)
{
if (Color == Color.White) {
Transition += (float)gameTime.ElapsedGameTime.TotalMilliseconds / 100f;
CountDown -= gameTime.ElapsedGameTime;
if (CountDown.TotalMilliseconds <= 0) {
return true;
}
}
return false;
}
public void Reset ()
{
Color = Color.TransparentBlack;
CountDown = TimeSpan.FromSeconds (5);
Transition = 0f;
}
public void Show ()
{
Color = Color.White;
CountDown = TimeSpan.FromSeconds (5);
}
}
The Reset method is used to reset the cell back to its default state where the monkey is hidden. This is called when the user taps a monkey. is used to set the timer to five seconds when the monkey appears onscreen. The Update method is called each frame to update the countdown timer, and helps us to figure out if a user has not tapped the monkey within the given five second timeframe.
Now that cells are defined, let’s define the grid. Create a new List field called grid:
List grid = new List();
Add the following code to the LoadContent method to calculate the display rectangles for the cell:
var viewport = graphics.GraphicsDevice.Viewport;
var padding = (viewport.Width / 100);
var gridWidth = (viewport.Width - (padding * 5)) / 4;
var gridHeight = gridWidth;
for (int y = padding; y < gridHeight*5; y+=gridHeight+padding) {
for (int x = padding; x < viewport.Width-gridWidth; x+=gridWidth+padding) {
grid.Add (new GridCell () {
DisplayRectangle = new Rectangle (x, y, gridWidth, gridHeight)
});
}
}
If you want your game to look good on all form factors, you need to take screen size into account, rather than hardcode positional values. GraphicsDevice.ViewPort provides us with a dynamic way to work with different form factors. In the code above, we add 10% of the screen width as padding to between the cells and calculate a width and height for the grid using the same property. We then loop through the (x,y) coordinates for each row and column and calculate the display rectangle.
Replace the Draw method with the code to draw our monkeys:
protected override void Draw (GameTime gameTime)
{
graphics.GraphicsDevice.Clear (Color.SaddleBrown);
spriteBatch.Begin ();
foreach (var square in grid)
spriteBatch.Draw (monkey, destinationRectangle: square.DisplayRectangle, color: Color.White);
spriteBatch.End ();
base.Draw (gameTime);
}
Finally, we want our game to run only in Portrait, so add the following code to the constructor:
graphics.SupportedOrientations = DisplayOrientation.Portrait;
Run the app, and you should see a grid full of monkeys!
The UI for MonkeyTap built with MonoGame and the Pipeline Editor.
With that, our user interface for our game built with MonoGame is complete. Follow our next post on adding game logic to complete your first game!