The Music Of Lunar Panda

Written by Adrian Killens on .

For those interested in the music of Lunar Panda, I've spent the morning going through the stuff that I composed for the game and put it all together in a nice little SoundCloud playlist along with some screenshots of where the music gets used in the game. If you're working on any non-profit stuff and you want to use any of it then please feel free.

Reporting performance statistics in your XNA code

Written by Dean Edis on .

In our first article we covered how we can write a simplified Photoshop-style API for displaying multiple textures on the screen, and we have since extended the code to several extra features:

Adding Parallax scrolling to your XNA code
Adding video layers to your XNA code

In this article we will add a class which allows us to display a customizable collection of your application’s runtime statistics. Two of the most important pieces of information to keep an eye on during development of an XNA project are:
● Frames per second (FPS)
● Garbage collection activity (See our earlier article.)

Allocating memory unnecessarily can have a negative effect on performance, especially when targeting platforms such as the Xbox (which has a different Garbage Collection implementation that on Windows machines). Generally speaking the less garbage collection required, the better. By being able to see at runtime how many collections are being made, you can get an early ‘heads up’ on potential bottlenecks you might be adding.

Here’s a screenshot showing a video playing on one layer, with another layer showing some runtime statistics:

The first line is fairly straight-forward - It displays your current frame rate (updated every 0.5 seconds). The next few lines show the total number of 0, 1, and 2 ‘generation’ of garbage collections. The example code is fairly light on memory allocations, so it may take a short while for the counts to start increasing.

As with any other of our Layer implementations, adding this new layer is trivial. Just create an instance of the new StatsLayer, and pass in the SpriteFont you wish to use for the display. I’ve included a hand-made font based on the ZX Spectrum, as it is clear and simple. For example (from the example code you can download below):

protected override void LoadContent()
{
 m_spriteBatch = new SpriteBatch(GraphicsDevice);
 // Define each layer.
 var videoLayer = new VideoLayer(Content.Load<Video>("Animal"), true)
 {
 AutoRepeat = true
 };

 var statsLayer = new StatsLayer(Content.Load<SpriteFont>("Speccy8x8"));
 // Create a Layers object, and define the order of the layers to display.
 m_rootLayers = new Layers();
 m_rootLayers.Add(videoLayer);
 m_rootLayers.Add(statsLayer);
}

 

Feel free to add to and customize the information that is displayed. For example, in some games you might like to display the number of on-screen sprites, sprite collisions, memory footprint, debug messages, etc… To do this just extend the StatsLayer code (or make a subclass which inherits from it):

public override void Draw(SpriteBatch spriteBatch)
{
 m_frameCount++;

var s = string.Format("{0} FPS\n{1} GC Gen 0\n{2} GC Gen 1\n{3} GC Gen 2", FPS, 
GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2));
 spriteBatch.DrawString(m_font, s, Vector2.Zero, Color.Yellow);

 // Add your code here.

}

You can download the full source (including a pre-built sample application showing its usage) from the link below.

DOWNLOAD SOURCE

Adding video layers to your XNA code

Written by Dean Edis on .

In our first article we covered how we can write a simplified Photoshop-style API for displaying multiple textures on the screen, and we have since extended the code to support parallax scrolling.

In this article we will add a short class which allows us to display Video objects as layers. In the future when we will develop our ‘layer’ code further we will be able to add post-processing filters (such as radial blur, grayscale, brightness/contrast), which could result in some great looking effects.

Here’s a screenshot showing video playing on one layer, with another layer showing information about the video:

(If you like the track then I recommend going to thebritishibm.com to view it in full, and more. It makes excellent music to code to!)

The code for this is quite straight-forward. When constructing a new VideoLayer object was pass in the Video we would like to play, and specify whether we want it to start playing immediately. We can optionally set whether we want the video to loop using the AutoRepeat property.

Here’s the new class:

public class VideoLayer : Layer, IDisposable
{
    private readonly Video m_video;
    private readonly bool m_autoPlay;
    private VideoPlayer m_player;
    private bool m_isFirstUpdate = true;

    /// <summary>
    /// Gets or sets a value indicating whether to automatically loop the video.
    /// </summary>
    public bool AutoRepeat
    {
        get { return m_player.IsLooped; }
        set { m_player.IsLooped = value; }
    }

    /// <summary>
    /// The constructor.
    /// </summary>
    /// <param name="video">The Video object to play.</param>
    /// <param name="autoPlay">Whether to start as video playing as soon as Update(...) is called.</param>
    public VideoLayer(Video video, bool autoPlay)
    {
        m_video = video;
        m_autoPlay = autoPlay;
        m_player = new VideoPlayer();
        AutoRepeat = true;
    }

    public void Play()
    {
        m_player.Stop();
        m_player.Play(m_video);
    }

    public void Stop()
    {
        m_player.Stop();
    }

    public override void Update(GameTime gameTime)
    {
        if (m_isFirstUpdate)
        {
            if (m_autoPlay)
                Play();
            m_isFirstUpdate = false;
        }

        base.Update(gameTime);
    }

    public override void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.GraphicsDevice.Clear(Color.Black);

        if (m_player.State != MediaState.Stopped)
            spriteBatch.Draw(m_player.GetTexture(), Origin, CreateWhite(ActualOpacity));
    }

    public void Dispose()
    {
        if (m_player == null)
            return;
        m_player.Dispose();
        m_player = null;
    }
}

As always, you can download the full source (including a pre-built sample application showing its usage) from the link below.

DOWNLOAD SOURCE

Adding Parallax scrolling to your XNA code

Written by Dean Edis on .

In our previous article we covered how we can write a simplified Photoshop-style API for displaying multiple textures on the screen.

In this article we will develop the code further to allow parallax scrolling. Parallax scrolling is used widely in games, and is useful for causing objects in a 2D scene to appear ‘distant’ by making them scroll at a slower rate than those ‘in front’.

To do this we build on our existing Layers class, as in principle we want to create a single ‘layer-able’ object containing multiple overlaid textures, creating ParallaxLayer.

For example:

First we need to allow the position of a Layer to be set. That’s easy enough - We just add a Vector2 Layer.Origin property and use this value in the TextureLayer.Draw(...) code:

public override void Draw(SpriteBatch spriteBatch)

{

 spriteBatch.Draw(m_texture, Origin, CreateWhite(ActualOpacity));

}

Then, when calling ParallaxLayer.Update(...) we scale the Origin of each Layer according to a preset amount:

public override void Update(GameTime gameTime)

{

 foreach (var layerInfo in m_layerInfos)

 layerInfo.Layer.Origin = Origin * layerInfo.MovementFactor;

 

 base.Update(gameTime);

}

 

When adding each layer to the ParallaxLayer object we also set the movementFactor value (typically in the range of 0.0f to 1.0f).

In the example code we use these values:

// Create a Layers object, and define the order of the layers to display.

m_rootLayers = new ParallaxLayer();

m_rootLayers.Add(cloudsLayer, 0.2f);

m_rootLayers.Add(mountainsFarLayer, 0.6f);

m_rootLayers.Add(mountainsNearLayer, 1.0f);

...to create a scene looking like this:

The scene can be scrolled using the arrow keys to show how each Layer moves relative to the others.

I hope you find the code useful!

DOWNLOAD SOURCE