Game Engine Tutorial Part III, Chapter 3 – Component Draw Order

One feature of the GameScreen is that it can draw components in whatever order they want to be drawn in. This can be useful for features like transparency, where transparent objects must be drawn last so that they can draw over the object behind them. To implement this, we will provide a property on the Component class that will tell its parent at what point in the draw call it would like to be drawn. This will simply be an integer, and higher numbers will be drawn later. To start with, we will add this property to the Component class. You will note that in it’s “set” accessor it tells its parent to update the draw order.

int drawOrder = 0;

public int DrawOrder
{
    get { return drawOrder; }
    set
    {
        this.drawOrder = value;

        if (Parent != null)
            Parent.PutComponentInOrder(this);
    }
}

We now need to add the PutComponentInOrder function to the GameScreen. For efficiency reasons and for simplicity, the Components in the list are actually stored in their draw order. When that order changes, we must move the component whose draw order changed to its new position. This way, when drawing, as we are iterating throught he list, we will draw the components in order.

// The components are stored in their draw order, so it is easy to loop
// through them and draw them in the correct order without having to sort
// them every time they are drawn
public void PutComponentInOrder(Component component)
{
    if (components.Contains(component))
    {
        components.Remove(component);

        int i = 0;

        // Iterate through the components in order until we find one with
        // a higher or equal draw order, and insert the component at that
        // position.
        for (i = 0; i < components.Count; i++)
            if (components[i].DrawOrder >= component.DrawOrder)
                break;

        components.Insert(i, component);
    }
}

The last thing we want to do here is make sure that the list is sorted when a new component is added, so we will call PutComponentInOrder in the AddComponent method.

public void AddComponent(Component Component)
{
    if (!components.Contains(Component))
    {
        components.Add(Component);
        Component.Parent = this;
        PutComponentInOrder(Component);
    }
}

Download the Code for this Chapter

12 Responses to “Game Engine Tutorial Part III, Chapter 3 – Component Draw Order” »

  1. Pingback by Innovation Engine Roadmap 2009-2010 | Innovative Games — October 20, 2009 @ 10:03 pm

    [...] Game Engine Tutorial Part III, Chapter 3 – Component Draw Order [...]

  2. Comment by jeremie mangue — October 21, 2009 @ 3:41 am

    hello sean, keep the good work. Nice to see your tutorial updated and more explanatory. Could be interesting to have small example illustrating stuff like draw order because I never get my head around it.

    alos How can I report a bug in jiglibX I found while back ?

    cheers

  3. Comment by droozzy — October 28, 2009 @ 8:08 am

    Hi,
    Great posts. I’ve been following your blog for a while now, and just wanted to point out that Google Reader only shows first 3-lines of your posts. Would be great if I could read the complete post :-)

    Thanks and keep up the great posts!

  4. Comment by Robert — October 29, 2009 @ 1:32 am

    Hey quick question again shawn, I know this allows us to sort based on opacity for sure, but could we also make a set of renderstates that stored specific values as well as the number value specific to that render state?

    Then when we go to draw said objects grab the spritebatch settings from there only if there values were different, otherwise just draw the object with out changing the spritebatch. This would reduce spritebatch calls to the graphics card and give us a faster render right?

  5. Comment by Brian West — November 21, 2009 @ 5:34 pm

    I have a question that maybe has been answered already but I don’t know. If it has please forgive me. Why are you insisting on reinventing the wheel? XNA already (now) supports everything you have written here. DrawableGameComponent allows you to set the DrawOrder of a component. Wouldn’t it be more useful to write a tutorial that explains how to use the features provided by XNA rather than rewrite them? I do like your ServiceProvider class better then the GameServiceCollection class though.

  6. Comment by Sean — January 3, 2010 @ 6:58 am

    I’ve stated this elsewhere, but I’m trying to do more than teach XNA here, I’m trying to show how to build a game engine, regardless of the language or framework. For example, while XNA may have this feature already, DirectX doesn’t, and you’re far more likely to be working with DirectX in the professional world. Plus, it’s a good demonstration of inheritance and some other common programming topics.

    Also, the “Game” class isn’t available when XNA is embedded in a windows form like when we get to the editor later on, so we actually need to reinvent this stuff here.

  7. Comment by Greg — January 21, 2010 @ 11:46 pm

    I don’t know if it really makes any difference but wouldn’t it be more efficient if the AddComponent method just added the Component in the correct order right away instead of first adding it, then calling PutComponentInOrder() (which will remove it and add it again in the correct order)?

  8. Comment by Sean — January 22, 2010 @ 12:20 am

    In this case it’s not worth the time to write the extra code, which would make it messier anyway. We want to keep the sort function separate so that it can be used when components change their draw order. Duplicating the sort code here would just be messy and would make not make a worthwhile performance increase at all.

  9. Comment by mhtregmr — January 27, 2010 @ 12:50 pm

    9I4h53 zqomyodrsfie, [url=http://dtkhpghwvpxa.com/]dtkhpghwvpxa[/url], [link=http://yekwhbncgfyr.com/]yekwhbncgfyr[/link], http://rjquizvmriub.com/

  10. Comment by MrSoundless — February 19, 2010 @ 2:10 pm

    Hi,
    First, I want to thank you for doing something like this which helps a lot of people.

    Second,
    I agree with Greg. You would remove more code then you would add. I got this now:

    public void AddComponent(Component component)
    {
    component.Parent = this;
    PutComponentInOrder(component);
    }

    public void PutComponentInOrder(Component component)
    {
    if (_components.Contains(component))
    _components.Remove(component);

    var i = 0;

    for (i = 0; i = component.DrawOrder)
    break;

    _components.Insert(i, component);
    }

  11. Comment by jay — July 25, 2010 @ 8:57 pm

    nice work sean, i’m having fun working through these, but being basically a n00b to coding i think it would help me if i knew where exactly to paste in the little snipits as i’m following along. trying to wrap my mind around all of this and i’d like to achieve a real, big picture understanding. i took plenty of math and physics in college and a couple c++ classes but it’s been a while. i keep stumbling on where to paste stuff but usually figure my way through it (by luck mostly)

    like between which set of braces or under which, uh, section or sub-section or whatever….i really should learn the names of these things….

    anyway, thanks for putting this up here, it’s been most helpful so far, i already worked through the stock tutorials and can’t wait to finish working through yours. i like your approach in basically writing your own engine, all the XNA stuff (obviously) is geared towards microsoft platforms. i appreciate the flexibility and the extra understanding

  12. Comment by Kevin — November 1, 2010 @ 1:22 pm

    Hi Sean,

    Correct me if I’m wrong but wouldn’t the fix be as simple as this:

    public void AddComponent(Component component) {
    if (!components_.Contains(component)) {
    PutComponentInOrder(component);
    component.Parent = this;
    }
    }

    public void PutComponentInOrder(Component component) {
    if (components_.Contains(component))
    components_.Remove(component);

    int i = 0;

    for (i = 0; i = component.DrawOrder)
    break;

    components_.Insert(i, component);
    }

    So, if the component is already in the list, you can remove it and insert it in its proper place. Otherwise, it must be a new element and just insert it wherever it needs to go.

RSS feed for comments on this post. TrackBack URI

Leave a comment