Category: Other Stuff

Best Kept Secrets of Peer Code Review

Posted by – January 16, 2010

I’ve just finished reading a book called “Best Kept Secrets of Peer Code Review” which is a free book, with free delivery from SmartBear who developed the code review tool called Code Collaborator.

You can get the book here

The book is quite short which makes it an easy read but has some very insightful views on the code review process. The title of the book is a little misleading as it suggests the book contains some content that isn’t already known to the wider audience. It doesn’t contain anything of the sort, but what it does contain is a very brisk overview what works with code review and what doesn’t, with some research and statistics to back it up.

As a developer we should already know the benefits of getting someone else to check over our work, we’ve all been there scratching our heads at a problem that we know should be easy to solve, yet for some reason you can’t see it. All it takes is for somebody else to look over your work and give back an objective opinion which will trigger you to realise what’s wrong, or in a case where you start to explain your work to someone and they don’t even get a chance to speak before you know what’s wrong.

In it’s simplest form this is a code review and in a more complex form you may print out pages of code to hand to other developers to read and point out any obvious mistakes. Both have pros and cons and are explained with good examples in this book. Finding the right balance for your work environment and staff is what is key to getting code reviews right.

So why don’t more teams have peer code review as part of their development process? There are a number of reasons that are explained but the one which I feel is the main objection to code review is the social aspects of what code review can mean to some people. In a lot of cases if the words “code review” are even mentioned it makes the author of code immediately defensive against the approach. “It will take me twice as long to do a check in”, “Don’t you trust me?”, “It’s a waste of time” etc. Some developers will think this is a way of measuring performance or quality of work, developers generally see defects/faults/bugs as a bad thing to be finding. Even before reading this book, I was one of the developers on the other side of the fence, I like to see other peoples work and give opinion, I also like other people to give opinion on my work. If I learn 1 new thing for every 10 times I ask someone to “look over my code” it’s worth all that effort on it’s own. If we also find 1 defect which means that’s 1 less ticket raised by testing or even worse, found by a customer, in my view this has always been worth the slight negative you may feel when someone finds a silly mistake you made. Defects are a good thing to be finding at any point in the development phase because it means less time spent testing and reimplementing the fix and retesting. This can easily be quantified into an actual cost which the book briefly explains and this can be used to justify the time/cost spent on doing code reviews in the first place.

When 2 developers get together to review some code and a handful of defects are found, we should see this as a very positive collaborative achievement and not be thought of as an exercise in embarrassing or undermining another developer where the defects were found. Developers all too often exist in a team but are very much a single entity and I believe code review is a great way to increase the communication in a team and also provide a way of increasing social bonds and not destroying them as many developers believe it will. Code reviews are about the code only, it is not about the reviewer showing he is a better developer because he found more defects in your code. The main goal is to produce a high quality product and the first step in doing that is producing high quality code with little defects.

This book has been a great refresher into why I love my job. The buzz you feel when your customer gives you some positive feedback and this book has helped keep fresh on my mind how we get this great reward. We produce high quality product to the customers requirements.

While I have done peer code review in the past, as i’m sure every developer has at some point, I for one have not used a defined “policy” in any one of my previous jobs. This is about to change, in my new job we cannot afford to have high QA costs and we certainly cannot afford to have lots of defects found by the customer. One way we hope to reduce this risk is by promoting the use of code review in our projects. We will try to encourage every developer to want to do a code review and not feel obliged to because it’s “process” but to help get the most out of code review we will work together to define a process which will guide us every time we do a review. This will be as much a team effort as the actual reviews are because we need every member of the team to buy into the benefits of peer code review or it wont work. Statistics cannot be used to judge a developers quality, statistics are used to show where you’re making the savings and highlight areas of common mistakes and reduce the amount of these that ever get to review.

My task now is to decide which style of code review we will encourage to our teams, document a process and define a guide to help reviewers and authors through the review process in the most efficient way.

I’m currently reviewing Smart Bear Code Collaborator which impressed me from the moment I set up my first review. It removes so much of the social problems, it almost removes the need to prepare for a review and it forces the review to keep on track and not get out of control. There are so many positives to using a tool like this I can see after doing only 5 reviews. I’m sure there are many more features I will find and I’m looking forward to seeing the statistics at the end of the trial.

Even if we decide the cost of the product is not in budget I will have benefited from using the trial as it makes it so easy to get people to buy into the benefits as soon as the first review ends.

When my trial is over I will post my findings and some details on what process we decided to take.

At the very least, if you’re a developer you should order this book. It’s free, it’s free delivery and it’s a short read. Pass it on to your team mates and try out some code reviews. They can actually be fun :)

A new direction

Posted by – October 30, 2009

It’s been a crazy few months. Working extremely hard on many different projects, some commercial, some for personal gain and some which are for you… the Community.

I’ve decided to keep my www.conkerjo.com blog but slightly change the direction of it to be more personal. So where will the technical articles and blog posts go? well, we’ve setup a new website called Sgt. Conker and you can see it here www.sgtconker.com
This site will host game development related articles among other things such as my open source projects and other projects and ideas which come from the other people involved.

I’d like to say a special thank you to Björn's and Catalin Zima for offering tons of support and help with the new web site. The are both part of the new council formed which currently has 6 members to help out with moderating the website and providing hot new news and infor for your pleasure.

Please welcome us by getting involved, post in the forum, submit articles, offer suggestions, ideas, critism. It’s all welcome.

Here’s hoping I won’t be so busy after mid november and I can blog more about some of the things I’ve been up to.

Redirecting the console output in c#

Posted by – September 17, 2009

Often when writing code in an agile way, the best way. We might write something like this.

 Console.WriteLine("I'm super awesome"); 

I don’t think it’s the correct way to do logging in your game or application. But such is life, stuff happens and we’re tasked with resolving it.

We need to get all these logging messages into some readable form inside my game, or app. This needs to be done by the time you wake up yesterday.

So how do we replace potentially hundreds and hundreds of Console.WriteLine’s?

Don’t panic, I have a solution. We can redirect the Console output to anything we want. All we need is an IO Stream and we can do whatever we like with it.

I decided to do this and output it to a label which scrolls in my application. It’s not the most ideal solution for viewing it either, but we went from not knowing W.T.F was going on, to seeing snippets of info fly by. It allowed us to progress with the next problem. This was a minor change and isn’t required to be in the final product so it doesn’t have to be “pretty” per say.

Here’s how I did it. I inherit from the class TextWriter and override the WriteLine method. I just happen to know all my logging calls are coming into WriteLine. Your situation may require more methods to override.

I expose an event which fires every time WriteLine is called and my app picks this up and displays it on screen. Here’s the full class

 public class TextBoxWriter : TextWriter
{
    public event Action<string> OnConsoleWriteLine;

    public override void Write(string message)
    {
        this.OnConsoleWriteLine(message);
    }

    public override Encoding Encoding { get { return Encoding.UTF8; } }

    public override void WriteLine(string message)
    {
        Write(string.Format("{0}\n", message));
    }
 } 

Once we have this class we simply have to redirect the console out put by using the Console.SetOut command.

 writer = new TextBoxWriter();
writer.OnConsoleWriteLine += new Action<string>(writer_WriteHappened);
Console.SetOut(writer); Console.SetOut(writer); 

Simple, yet effective. I should get back to work :)

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

I've moved

Posted by – September 4, 2009

I’ve moved my blog from http://conkerjo.wordpress.com and it looks like I’ve managed to import all my old posts with only one issue. I can’t seem to display some characters using this font. See previous post.

I can however link to his site. Here’s The Week In Code (X) :O

The Week in Code by Björn

Posted by – July 14, 2009

Björn (or boki) has written his 7th instalment of The Week in Code. Hit the RSS button and maybe he’ll feel obliged to keep it up and add some more. I’m in there 2 weeks on the trot by the way :D

Björn’s XNA Adventures

XNA & Game A.I

Posted by – July 7, 2009

Over the past few weeks I have been developing an A.I middleware library for use with XNA games. I’ve spent a lot of this time in google searching for A.I articles and samples. It’s a force of habit to append XNA to the end of my code related searches and I wasn’t finding the information I needed to get the inspiration for my A.I library. I did figure out how to use google eventually and found lots of good, general A.I articles and samples. Most samples are c++ but it’s more about the concepts of A.I I was looking for than the samples.

At some point in the very near future I will be releasing the source code to this library along with a sandbox for you to see how to use it and to play around with it. One thing I’m struggling with is deciding what small chunks of A.I I should demonstrate. If you have some ideas of what you would like from an A.I sandbox please comment on this post and we can discuss.

In the meantime, here is a bunch of links I’ve been reading over the past few weeks relating A.I and some XNA specific ones I did find.

 

XNA Creators Club Online

Other

Spatial hashing implementation for fast 2D collisions

Posted by – June 13, 2009

This is a sample prototype I wrote to fix a performance limitation with collision checking in SBARG. So what is spatial hashing? Here is a good 1 liner I will borrow from the source material i used.

“Spatial hashing is a process by which a 3D or 2D domain space is projected into a 1D hash table.” Optimization of Large-Scale, Real-Time Simulations by Spatial Hashing

So why do we need it?

Well, for me it was a problem in my collision code and my A.I code which was trying to find nearby objects to check collisions for. Due to my brute force nature if I had 10 monsters in the world there would be 10*10 = 100 collision checks in every update. Now ramp the number up to 100 to be a bit excessive and we end up with 100*100=10,000 collision checks. This makes the cpu cry like a little baby as I’m sure you can imagine. To rectify this we need to reduce the amount of collision checks we need to do in the first place. This is where spatial hashing comes in handy.

Imagine the game world in a flat 2d grid. 100 by 100 pixels and each cell was 25 by 25 pixels. Now number the cells from left to right, top to bottom 0 onwards. You will end up with something like this. The orange circles are the game objects, in my case, monsters.

image

Each cell is a bucket of game objects and a unique hash id. If we imagine the bucket as a list of 16 buckets, 0-15 cells and placed the game objects in that bucket. It might look something like this.

image

This is our 1D grid mentioned in the introduction.

It’s a simple premise really, any item in bucket 3 for example, cannot possibly collide with something in bucket 9. This reduces the amount of times we need to cycle the nearby objects but also dramatically reduce the amount of times we need to check if a collision is happening.

Ok, so the above implementation is fine as long as a game object only ever exists in 1 bucket. But what if it crosses a line and exists in more than 1 bucket. To resolve this I imagined a box around each game object, and I calculated the hash id for each corner of the box. I then populate a List<GameObject> going through each bucket the game object is in. Sounds simple ?

Let me show you some of this theory in code.

First we need a game object. For this sample all we need is a position and a radius.


    public class GameObject
    {
        public Vector2 Position { get; set; }
        public float Radius { get; set; }
    }

We create a new class to store the grid data in including the buckets. I’m terrible at naming classes so I called it SpatialManager. I gave this class a Setup method which takes a full scenewidth, height and a cellsize. In our example this would be 100,100,25


    public void Setup(int scenewidth, int sceneheight, int cellsize)
    {

We can work out how many buckets we need by first calculating the rows and cols then simply create a new Dictionary of buckets to the tune of Rows*Cols. I also store these variables passed in for future use.


    Cols= scenewidth / cellsize;
    Rows= sceneheight / cellsize;
    Buckets = new Dictionary<int  , list><gameobject>(Cols * Rows);

    for (int i = 0; i < Cols*Rows; i++)
    {
        Buckets.Add(i, new List());
    }

    SceneWidth = scenewidth;
    SceneHeight = sceneheight;
    CellSize = cellsize;
}

Each update, we need to clear out the buckets and re calculate the buckets each game object are in. I created a method called ClearBuckets to start fresh.


   internal void ClearBuckets()
   {
       Buckets.Clear();
       for (int i = 0; i < Cols * Rows; i++)
       {
           Buckets.Add(i, new List());
       }
   }

We now need a method to register a game object into the buckets it sits in.


    internal void RegisterObject(GameObject obj)
    {
        List cellIds= GetIdForObj(obj);
        foreach (var item in cellIds)
        {
            Buckets[item].Add(obj);
        }
    }

As you can see, the code retrieves a list of cellids to add the game object to.

In the GetIdForObj method it calculates the cell id for each corner of the game object.

If we were just checking the position of the game object the calculation would be.

float width = SceneWidth / CellSize; // 100 / 25

int hashid=(int)(

    (Math.Floor(position.X / CellSize)) +

    (Math.Floor(position.Y / CellSize)) * width);

We need to do this for each corner and add our game to each bucket.

The GetIdForObj method looks like this.


    private List GetIdForObj(GameObject obj)
    {
        List bucketsObjIsIn = new List();

        Vector2 min = new Vector2(
            obj.Position.X - (obj.Radius),
            obj.Position.Y - (obj.Radius));
        Vector2 max = new Vector2(
            obj.Position.X + (obj.Radius),
            obj.Position.Y + (obj.Radius));

        float width = SceneWidth / CellSize;
        //TopLeft
        AddBucket(min,width,bucketsObjIsIn);
        //TopRight
        AddBucket(new Vector2(max.X, min.Y), width, bucketsObjIsIn);
        //BottomRight
        AddBucket(new Vector2(max.X, max.Y), width, bucketsObjIsIn);
        //BottomLeft
        AddBucket(new Vector2(min.X, max.Y), width, bucketsObjIsIn);

	return bucketsObjIsIn;
    }

And here is the AddBucket method which uses the calculation described above and adds it to the list of bucket id’s to add to.


    private void AddBucket(Vector2 vector,float width,List buckettoaddto)
    {
        int cellPosition = (int)(
                   (Math.Floor(vector.X / CellSize)) +
                   (Math.Floor(vector.Y / CellSize)) *
                   width
        );
        if(!buckettoaddto.Contains(cellPosition))
            buckettoaddto.Add(cellPosition);

    }

Now that we have our grid of buckets. It’s a very simple retrieval process. I added a method to get the nearby objects of a given object. This uses the GetIdForObj method and populates a list of GameObject’s and returns once complete. This is the key part to this solution, you only now need to check items which are actually nearby and not items the other side of the theoretical world.


    internal List GetNearby(GameObject obj)
    {
        List objects = new List();
        List bucketIds = GetIdForObj(obj);
        foreach (var item in bucketIds)
        {
            objects.AddRange(Buckets[item]);
        }
        return objects;
    }

So that’s it. Now you can do your normal collision checking by retrieving nearby GameObjects. And here’s a screenshot to prove it.

I’ve placed my mouse over one of the GameObjects and it’s highlighted all nearby items. Notice how they cross over cells. This is because the item i hover over is on the line and exists in multiple cells. Also notice the amount of checks it has to do. For brute force it has to do 250,000 bounding box collision checks. For spatial hashing, it checks only 4840 times. Wicked.

SpatialHashing

And what would a sample be without source code?

Enjoy

Link To Sample

Simply RenderTargets

Posted by – May 26, 2009

Somebody in the #xna IRC channel just asked how to use RenderTargets to only draw a portion of the screen. Here’s my answer.

I guessed from his brief description he might have a game scene which didn’t look like this

 

background

And the result he wanted, was something almost like … this ?

pieview

What you see here is the game scene drawn, with a triangle portion visible and the rest not so much. My favourite way to achieve this is to use 2 RenderTargets, A VERY simple Effect(shader) and good old SpriteBatch. So what do we use all this for?

First we need to draw the game scene. There is a way around this but to make things easier to understand we will draw this to a RenderTarget. Simply put, a RenderTarget is an imaginary “screen” to draw to which you can specify the size of. Then once done, you can use the texture like any normal Texture2D you might load from the Content Pipeline.

To draw the scene we first want to set the correct RenderTarget, then use spritebatch just like you would to draw any other sprite. Like this.


            GraphicsDevice.SetRenderTarget(0, _gameRT);
            //Clear the RT screen
            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin();
            //Draw the game
            spriteBatch.Draw(
                _gameBackground,
                Vector2.Zero,
                Color.White);

            spriteBatch.End();

Simple uh?

Now we need to create another RenderTarget, and Draw a triangle to it. This will never be displayed in the final scene. Although with the RenderTarget it allows you to if you so desire, maybe for debugging purposes?



            GraphicsDevice.SetRenderTarget(0, _lightRT);
            //Clears the screen transparent.
            GraphicsDevice.Clear(Color.TransparentBlack);
            spriteBatch.Begin();

            spriteBatch.Draw(
                _triangle,
                Vector2.Zero,
                Color.White);

            spriteBatch.End();

This code is almost identical to the last except we draw the _triangle Texture which looks like this.

triangle

And we use the color transparent black.

The final thing we need to do now is draw it to the scene.

If we just draw the triangle on top of the game scene you will see the game scene with a white triangle on top. This isnt what we want. So we use a shader to take the game scene, and change the alpha channel corresponding to the white triangle. Wherever there is a solid non transparent color pixel, this will be set to a fully non transparent pixel in the game result, however, a transparent pixel in the triangle image will result in a completely transparent pixel in the final result. Resulting in you not being able to see that pixel. The final result is like this.

pieview

 

The shader code is very simple. It is a pixel shader which takes a AlphaTexture parameter which is the texture taken from the triangle RT. It takes the alpha from that texture, and sets the coresponding pixel on the final image to be the same.


float4 PixelShader(float2 texCoord: TEXCOORD0) : COLOR
{
	float4 Color = tex2D(ScreenS, texCoord);
    float alphaLayerAlpha = tex2D(AlphaSampler, texCoord).a;
	Color.a=alphaLayerAlpha;
    return Color;
}

Cool?

To use this we just create a new Effect variable and load it in LoadContent. Call Begin/End in the appropriate places, set the parametar and hey presto. A RESULT!!!


_myEffect.Parameters["AlphaTexture"].SetValue(_lightRT.GetTexture());
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
_myEffect.Begin();
_myEffect.CurrentTechnique.Passes[0].Begin();
spriteBatch.Draw(_gameRT.GetTexture(),
    Vector2.Zero,
    Color.White);

_myEffect.CurrentTechnique.Passes[0].End();
_myEffect.End();
spriteBatch.End();

To get a better grasp of the code you can download the sample project here.

DOWNLOAD

As I said, Someone in IRC literally just asked. So I knocked this up. Apologies for the rushed post :) BACK TO SBARG!!!