Building a scrolling sprite-based star field background

Creating the project

In this simple tutorial we want to create a scrolling sprite-based star field background using Xamarin Studio and the MonoGame that is an open source implementation of the Microsoft XNA 4.x Framework. This page lists the requirements for creating a MonoGame project on Windows.

Open Xamarin Studio and create a new MonoGame Windows OpenGL Application project called TwoDimensionalStarField. Open Microsoft Paint or your favourite image editor and create a new 2 by 2 pixel image and fill it with white. Save the image as STAR.BMP in a temporary location. Back in Xamarin Studio, right-click on Content folder and select Add | Add Files. Browse to the image you created and click on Ok. Add TitleScreen.PNG to your project too.

Add declarations to the Game1 class for game states and textures:

enum GameStates {TitleScreen, Playing};
GameStates gameState = GameStates.TitleScreen;
Texture2D titleScreen;
Texture2D star;

Update the LoadContent() method to load textures:

star = Content.Load(@"STAR");
titleScreen = Content.Load (@"TitleScreen");

You need to add a basic template for the Update() method before to call base.Update():

switch(gameState)
{
case GameStates.TitleScreen:
	if ((Keyboard.GetState ().IsKeyDown (Keys.Space))) {
		gameState = GameStates.Playing;
	}
	break;
case GameStates.Playing:
	// ...
	break;
}

Add a basic template for the Draw() method before the call to base.Draw() and put it between spriteBatch.Begin() and spriteBatch.End() methods:

if (gameState == GameStates.TitleScreen) {
	spriteBatch.Draw (
		titleScreen,
		new Rectangle(0, 0,
			this.Window.ClientBounds.Width,
			this.Window.ClientBounds.Height),
		Color.White
	);
}

if(gameState == GameStates.Playing) {
	// ...
}

Up to this point we have created the skeleton of our Update() and Draw() method. Now you can execute your project (hit Alt + F5) to see that the title screen is displayed.

Building the Star class

Add a new class to the project called Star.cs and then include the following declarations to the class’ using area:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

Add the following properties to the Star class:

private Texture2D Texture { get; set; }
public Color TintColor { get; set; }
public Vector2 Location { get; set; }
private Vector2 Velocity { get; set; }
private Rectangle InitialFrame { get; set; }

The TintColor member stores color of each star that will be used when the star is drawn. The location of the star will be tracked via the Location vector while the speed and direction at which the star is moving is stored in Velocity.
Add the following constructor to the Star class:

public Star(
	Vector2 location,
	Texture2D texture,
	Rectangle initialFrame,
	Vector2 velocity)
{
	Location = location;
	Texture = texture;
	InitialFrame = initialFrame;
	Velocity = velocity;
}

This constructor just directly sets the members to the passed parameter values. Now You need to add the following property and methods to the Star class:

public Rectangle Destination
{
	get {
		return new Rectangle (
			(int)Location.X, (int)Location.Y,
			InitialFrame.Width, InitialFrame.Height
		);
	}
}
public void Update(GameTime gameTime)
{
	float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
	Location += (Velocity * elapsed);
}
public void Draw(SpriteBatch spriteBatch)
{
	spriteBatch.Draw (
		Texture, Destination, InitialFrame, TintColor
	);
}

The Destination property builds a new Rectangle based on the star’s current screen location and the width and height of the InitialFrame. The Update() method adds the sprite’s velocity to the sprite’s location. Since velocity is stored as the change over one second, multiplying it by the gameTime.ElapsedGameTime.TotalSeconds (If the game is running at 60 frames per second the value is likely to be 1 / 60 = 0.0166 seconds) determines the distance moved over a single frame. The Draw() method consists of a single call to the SpriteBatch.Draw() method using third overload of the method.

Building the StarField class

Let’s put our Star class to use by creating a scrolling star field. We can use an empty white sprite in combination with the TintColor parameter of the SpriteBatch.Draw() method to draw squares of any color we wish. This is why we have created STAR.BMP. For creating the star field, we will create 300 stars and place them on the screen randomly. They will have a velocity that will slowly draw them down the screen. The StarField class will be responsible for creating the stars and determining when they reach at the bottom of the screen. When this happens, they will be created again at the top of the screen at a random location.

Add a new class called StarField and then add the following using directives to the class’ using area:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

Add the following declarations to the StarField class:

private List stars = new List();
private int ScreenWidth { get; set; }
private int ScreenHeight { get; set; }
private Random rand = new Random();
private Color[] colors = {
	Color.White, Color.Yellow, Color.Red
};

Add a constructor to the StarField class:

public StarField(
	int screenWidth,
	int screenHeight,
	int starCount,
	Vector2 starVelocity,
	Texture2D texture,
	Rectangle initialFrame
)
{
	ScreenWidth = screenWidth;
	ScreenHeight = screenHeight;

	for(int x = 0; x < starCount; x++)
	{
		stars.Add (
			new Star(
				new Vector2(rand.Next(0, screenWidth),
					rand.Next(0, screenHeight)),
				texture,
				initialFrame,
				starVelocity)
		);
	}
	foreach (Star star in stars) {
		star.TintColor = colors[rand.Next(0, colors.Length)];
		star.TintColor *= (float)(rand.Next (30, 80) / 100f);
	}
}

We will store each star in the stars list. It makes it simple to update and draw them using a foreach loop. When the stars are created, a color will be selected randomly from the colors array for each star. In the class constructor we will create 300 stars and each star is assigned a random location.  The TintColoris then multiplied by a random value between 0.30f and 0.79f, making the star semi-transparent. Add the Update() and Draw() methods to the StarField class:

public void Update(GameTime gameTime)
{
	foreach (Star star in stars)
	{
		star.Update (gameTime);
		if (star.Location.Y > ScreenHeight) {
			star.Location = new Vector2 (rand.Next(0, ScreenWidth),0);
		}
	}
}
public void Draw(SpriteBatch srriteBatch)
{
	foreach(Star star in stars)
	{
		star.Draw(srriteBatch);
	}
}

A foreach loop updates each star in the stars list. The method then checks the star’s Location property’s Y to determine if the star has reached at the bottom of the screen. If it happens, the star’s location is assigned a new Location with a random X and a Y component of zero, putting the star at a random location at the top of the screen. The Draw() method simply uses a foreach loop to passes along the spriteBatch object to each of the individual stars in the stars list.

Viewing the StarField in action

Add the following declaration to the Game1 class:

StarField starField;

Now you have to initialize the starField object. In the LoadContent() method of the Game1 class, place this code after the titleScreen texture
is loaded:

starField = new StarField (
	this.Window.ClientBounds.Width,
	this.Window.ClientBounds.Height,
	300,
	new Vector2(0, 100f),
	star,
	new Rectangle(0, 0, 2, 2)
);

In the Upate() method, simply call the Update() method of starField class and place it to the GameStates.Playing section of the switch statement you created earlier:

starField.Update (gameTime);

In the Draw() method, change the background color from Color.CornflowerBlue to Color.Black.  Still in the Draw() method, call the Draw() method of starField and place it to the if block containing GameStates.Playing:

starField.Draw (spriteBatch);

Now Run the project and observe the star field.

Leave a comment