Category: K.I.S.S

K.I.S.S – C# Properties

Posted by – September 10, 2009

Keeping up with the K.I.S.S principle my previous post prompted an interesting debate in the #xna IRC channel.

Somebody commented

“User> Also, "public Vector2 Position { get; set; }" will transmit some bad habits to noobs. :]”

&

“<User> It expands it into a function call. If the get and set is public, it may as well be a public field.”

I missed most of the debate but here’s my take on things.

Why should we use auto properties as opposed to being maticulous and writing out the private variable? Or why bother with a property at all if you can’t be bothered to write the private variable and set and return it?

Firstly, I don’t see how it produces a bad habit. I come from a background where having to write a private accessor every time I needed a property was a very tedious task. Especially when dealing with hundreds of classes at the start of a large project, so this was a very welcome addition to .net for me as writing a private accessor just to return it and set it felt like a waste and left me with a ton of private variables I didn’t really need.

A few arguments for using them are.

  • It follows the K.I.S.S principle.
  • It looks a lot cleaner and has a smaller code footprint than writing a private property too.
  • They’re so easy to implement using the Visual Studio Snippet feature. prop <tab> type <tab> name <enter>
  • It allows you to maintain the API while giving you room for flexibility in the future to change the functionality of the get/set.
  • If a third party relied on using reflection for API, fields are treat differently to properties.

 

So what really happens when we do use these auto properties.

Not surprisingly it does something very similar to what you would do if you write the private accessor yourself. Here’s an example.

Here is my own property with my own private variable. This took blood sweat and tears.

private int myvalue;

public int MyValue
    {
        get { return myValue; }
        set { myValue = value; }
    }

 

Here is my auto property for the lazy people.

 

public int MyValue { get; set; };

And here is what your code looks like after you compile an auto property.

[CompilerGenerated]
private int &lt;myproperty&gt;k__BackingField;

public int MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.&lt;myproperty&gt;k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        this.&lt;myproperty&gt;k__BackingField = value;
    }
}

 

It’s just doing the same thing, except adding an attribute to say it was generated by the compiler.

Over the course of a large application or a game, you would be amazed at how much time this saves, it keeps it simple and allows you to tighten up property get/set methods later in the development cycle.

There are a lot of other differences between Fields and Properties in c# but the main ones which effect this discussion are listed above.

Thanks to Björn for giving me the nudge to post.

This post is sponsered by Björn’s XNA Adventures

K.I.S.S – Fading between images with XNA

Posted by – September 6, 2009

In my first Keep It Simple Stupid (K.I.S.S) post I wanted to write about fading between 2 images.

Fading between 2 images is a very simple task using XNA, yet I’ve seen some severely over engineered solutions in the past. Here’s my take on the problem.

We need to fade from one image which is currently displaying on screen to another image we have stored in memory.

Here are 3 states of 2 images fading between each other.

The Start

blogimage1

The Fade

blogimage2

The Result

blogimage3

To keep it simple we use functionality within the XNA framework so we don’t have to write our own. This can be done using the SpriteBatch AlphaBlend which just happens to be the default option when calling Begin on a SpriteBatch.

Simply call Begin, draw the image currently on screen at a reduced alpha, then draw the image you want to transition to over the top with a alpha set to the other extreme.

I created a class which takes care of the drawing and alpha transitioning. Once we create an instance of the CustomImage class we must call Update, passing it the elapsed time since the last frame and also call the Draw method to draw the transition.

If there is no transition the CustomImage will simply draw the Image set at full opacity.

We define the amount of time to take in a transition in the constructor of the CustomImage or it can be changed via the TransitionTime property.

To start a transition just pass a Texture2D to the TransitionTo method. This will begin the process of fading between the two images and will completely switch over to the new image once complete.

Here is the full class implementation.

 public class CustomImage
{
    private float timer;
    public CustomImage(Texture2D initialImage, Vector2 position, Vector2 origin, float transitionTime)
    {
        this.Image = initialImage;
        this.TransitionTime = transitionTime;
        this.Color = Color.White;
        this.Rotation = 0;
        this.Position = position;
        this.Origin = origin;
    }

    public float TransitionTime { get; set; }

    public Texture2D Image { get; private set; }

    public Texture2D ToImage { get; private set; }

    public Vector2 Origin { get; set; }

    public Vector2 Position { get; set; }

    public Color Color { get; set; }

    public float Rotation { get; set; }

    public void TransitionTo(Texture2D image)
    {
        if (this.ToImage != null)
        {
            return;
        }
        this.ToImage = image;
        this.timer = 0;
    }

    public void Draw(SpriteBatch batch)
    {
        if (this.ToImage == null)
        {
            batch.Draw( this.Image, this.Position, null, this.Color, this.Rotation, this.Origin, 1f, SpriteEffects.None, 0);
        }
        else
        {
            int alpha = (int)((this.timer / this.TransitionTime) * 255);
            this.DrawImage(batch, this.Image, 255 - alpha);
            this.DrawImage(batch, this.ToImage, alpha);
        }
    }

    public void Update(float elapsed)
    {
        // We must be transitioning
        if (this.ToImage != null)
        {
            this.timer += elapsed;
            if (this.timer &amp;amp;amp;gt;= this.TransitionTime)
            {
                this.Image = this.ToImage;
                this.ToImage = null;
            }
        }
    }

    private void DrawImage(SpriteBatch batch, Texture2D texture, int alpha)
    {
        batch.Draw( texture, this.Position, null, new Color(this.Color, (byte)alpha), this.Rotation, this.Origin, 1f, SpriteEffects.None, 0);
    }
} 

&nbsp

To use this class we pass a Texture2D, a position, an origin and a length of time we want a transition to take.

Calling Draw will draw the image set until you pass a Texture2D to the TransitionTo method.

Here’s is the full Game code to show how I used this class in the sample which you can download at the end of the page.

 public class Game1 : Microsoft.Xna.Framework.Game
{
    private GraphicsDeviceManager graphics;
    private SpriteBatch spriteBatch;
    private SpriteFont font;
    private CustomImage image1;
    private CustomImage image2;
    private float storedTimer = 2;
    private KeyboardState currentKeyboardState, lastKeyboardState;
    private Vector2 imageSize = new Vector2(400, 300);

    public Game1()
    {
        this.graphics = new GraphicsDeviceManager(this);
        this.Content.RootDirectory = &quot;Content&quot;;
    }

    private Vector2 ScreenSize
    {
        get
        {
            return new Vector2(this.GraphicsDevice.Viewport.Width, this.GraphicsDevice.Viewport.Height);
        }
    }

    protected override void Initialize()
    {
        base.Initialize();
    }

	protected override void LoadContent()
    {
        this.spriteBatch = new SpriteBatch(GraphicsDevice);
        this.font = this.Content.Load&lt;spritefont&gt;(&quot;Fonts/Arial&quot;);

		Vector2 position = new Vector2((this.ScreenSize.X / 4), this.ScreenSize.Y / 2);
        this.image1 = new CustomImage(this.Content.Load&amp;lt;texture2d&amp;gt;(&quot;Textures/Image1&quot;), position, this.imageSize / 2, this.storedTimer);

		position.X += this.ScreenSize.X / 2;
        this.image2 = new CustomImage(this.Content.Load&amp;lt;texture2d&amp;gt;(&quot;Textures/Image2&quot;), position, this.imageSize / 2, this.storedTimer);
    }

	protected override void UnloadContent()
    {
    }

    protected override void Update(GameTime gameTime)
    {
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        {
            this.Exit();
        }

		this.lastKeyboardState = this.currentKeyboardState;
        this.currentKeyboardState = Keyboard.GetState();

		float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

		this.HandleInput();

		this.image1.Update(elapsed);
        this.image2.Update(elapsed);

		base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        this.GraphicsDevice.Clear(Color.Black);

		this.spriteBatch.Begin();

		StringBuilder instructions = new StringBuilder();
        instructions.Append(&quot;Space : Transition&quot;);
        instructions.Append(Environment.NewLine);
        instructions.Append(&quot;PgUp / PgDwn : Increase / Decrease Timer&quot;);
        instructions.Append(Environment.NewLine);
        instructions.Append(string.Format(&quot;Transition Time : {0}&quot;, this.storedTimer));

		this.spriteBatch.DrawString(this.font, instructions, new Vector2(25), Color.White);

		this.image1.Draw(this.spriteBatch);
        this.image2.Draw(this.spriteBatch);

		this.spriteBatch.End();

		base.Draw(gameTime);
    }

    private void HandleInput()
    {
        if (this.IsNewKeyPress(Keys.Space))
        {
            this.image1.TransitionTo(this.image2.Image);
            this.image2.TransitionTo(this.image1.Image);
        }

        if (this.IsNewKeyPress(Keys.PageDown))
        {
            this.storedTimer -= 0.25f;
            this.image1.TransitionTime = this.image2.TransitionTime = this.storedTimer;
        }

		if (this.IsNewKeyPress(Keys.PageUp))
        {
            this.storedTimer += 0.25f;
            this.image1.TransitionTime = this.image2.TransitionTime = this.storedTimer;
        }
    }

    private bool IsNewKeyPress(Keys keys)
    {
        return this.currentKeyboardState.IsKeyUp(keys) &amp;amp;amp;amp;&amp;amp;amp;amp; this.lastKeyboardState.IsKeyDown(keys);
    }

    private void DrawImage(Texture2D image, Vector2 position)
    {
        this.spriteBatch.Draw(image, position, null, Color.White, 0, this.imageSize / 2, 1, SpriteEffects.None, 0);
    }
} 

 

You can download the sample project with complete working sample here