Event forwarding

Written by Dean Edis on .

I was having a coding session recently and needed a class to 'pass on' an event fired from a another class.

E.g.
ClassA 'has a' private ClassB. ClassB has an EventB event which occasionally fires.
I want ClassA to have an EventA event which fires whenever EventB does.

My first approach was simple: Have ClassA subscribe to ClassB.EventB. When it receives the event it fires its own EventA.

Did you know...

A simpler approach is to use a custom event subscription:

class ClassA 
{ 
    private ClassB m_b = new ClassB(); 

    public event EventType EventA 
    { 
        add { m_b.EventB += value; } 
        remove { m_b.EventB -= value; } 
    } 
} 

Now, anything subscribing to ClassA.EventA will get its subscription passed on to ClassB, but all without the caller having any direct access to ClassB!

Clean and simple...

Lunar Panda Deluxe Now Available on PC

Written by Adrian Killens on .

Some fantastic news for all you Panda fans out there! Lunar Panda Deluxe has literally just been approved by the lovely people at Desura and is now available to purchase for the PC. So what are you waiting for? Grab yourself a copy today and help support us so we can make more excellent games that may or may not include a Panda ;-)

Buy Lunar Panda Deluxe (PC)

Drawing Dialog Backgrounds in XNA

Written by Dean Edis on .

The fact that XNA comes with minimal built-in ability to display attractive-looking UIs can be seen as both an advantage and a disadvantage.

When you're writing an application that needs to put up a dialog though (and you don't want to break XNA's cross-platform support by using WIN32 calls!), it can be annoying!

We're in the process of writing the infrastructure for our next game, and in it we'd like to be able to display a range of attractive UI styles, without too much overhead.

So to help with this I've written code to display a dialog background using only a template image. The class ensures that the dialog can be displayed at any sensible size, without introducing unpleasant 'stretch' artifacts.

 

To start off with, let's see an example of a dialog template, and how it could be made to appear on the screen:

To display this on our XNA screen at any given size, we first need to split the bitmap into a 3x3 grid of 'virtual' regions. (I've also reduced the size of the template, as it doesn't need to be too big.)

The corner areas will be blitted to the screen without any scaling applied to them. The top and left edges will be stretched in one direction only, and the centre-most region will be scaled in both direction as appropriate.

The result is nice-looking dialog background, regardless of the dimensions of the original template image - You only need to define the size of the 'margin' on your original template image such that it incloses each of the corners.

The code is quite straight-forward, and easy to import into your own projects. Just create an instance of BorderBitmap, passing in your dialog texture and the pixel size of a ‘corner’, then call Draw() from your display code.

Finding dialog templates online isn't too tricky. I certainly recommend here:
http://opengameart.org/

 

I hope you find this useful!

/// <summary>
/// For drawing a textured bitmap where the corner sections remain unscaled but the remaining area is stretched to the desired screen size.
/// </summary>
public class BorderBitmap
{
    private readonly Texture2D m_texture;
    private readonly int m_cornerPixels;

    public BorderBitmap(Texture2D texture, int cornerPixels)
    {
        if (texture == null)
            throw new ArgumentNullException("texture");

        m_texture = texture;
        m_cornerPixels = cornerPixels;
    }

    public void Draw(SpriteBatch spriteBatch, int x, int y, int width, int height)
    {
        var sourceArea = new Rectangle(0, 0, m_texture.Width, m_texture.Height);
        var sourceInnerArea = new Rectangle(m_cornerPixels, m_cornerPixels, sourceArea.Width - 2 * m_cornerPixels, sourceArea.Height - 2 * m_cornerPixels);

        spriteBatch.Draw(m_texture, new Rectangle(x + m_cornerPixels, y + m_cornerPixels, width - 2 * m_cornerPixels, height - 2 * m_cornerPixels), sourceInnerArea, Color.White);

        if (m_cornerPixels > 0)
        {
            DrawSides(spriteBatch, x, y, width, height, sourceInnerArea);
            DrawCorners(spriteBatch, x, y, width, height, sourceInnerArea);
        }
    }

    private void DrawCorners(SpriteBatch spriteBatch, int x, int y, int width, int height, Rectangle sourceInnerArea)
    {
        // Top-left
        spriteBatch.Draw(m_texture, new Vector2(x, y), new Rectangle(0, 0, m_cornerPixels, m_cornerPixels), Color.White);

        // Top-right
        spriteBatch.Draw(m_texture, new Vector2(x + width - m_cornerPixels, y), new Rectangle(sourceInnerArea.Right, 0, m_cornerPixels, m_cornerPixels), Color.White);

        // Bottom-right
        spriteBatch.Draw(m_texture, new Vector2(x + width - m_cornerPixels, y + height - m_cornerPixels), new Rectangle(sourceInnerArea.Right, sourceInnerArea.Bottom, m_cornerPixels, m_cornerPixels), Color.White);

        // Bottom-left
        spriteBatch.Draw(m_texture, new Vector2(x, y + height - m_cornerPixels), new Rectangle(0, sourceInnerArea.Bottom, m_cornerPixels, m_cornerPixels), Color.White);
    }

    private void DrawSides(SpriteBatch spriteBatch, int x, int y, int width, int height, Rectangle sourceInnerArea)
    {
        // Top
        spriteBatch.Draw(m_texture, new Rectangle(x + m_cornerPixels, y, width - 2 * m_cornerPixels, m_cornerPixels), new Rectangle(sourceInnerArea.Left, 0, sourceInnerArea.Width, m_cornerPixels), Color.White);

        // Bottom
        spriteBatch.Draw(m_texture, new Rectangle(x + m_cornerPixels, y + height - m_cornerPixels, width - 2 * m_cornerPixels, m_cornerPixels), new Rectangle(sourceInnerArea.Left, sourceInnerArea.Bottom, sourceInnerArea.Width, m_cornerPixels), Color.White);

        // Left
        spriteBatch.Draw(m_texture, new Rectangle(x, y + m_cornerPixels, m_cornerPixels, height - 2 * m_cornerPixels), new Rectangle(0, m_cornerPixels, m_cornerPixels, sourceInnerArea.Height), Color.White);

        // Right
        spriteBatch.Draw(m_texture, new Rectangle(x + width - m_cornerPixels, y + m_cornerPixels, m_cornerPixels, height - 2 * m_cornerPixels), new Rectangle(sourceInnerArea.Right, m_cornerPixels, m_cornerPixels, sourceInnerArea.Height), Color.White);
    }
}