This tutorial is going to be a quick one. I originally had this as part of the next one, but it is getting to be too long for one post so I’m splitting it into two parts. In this chapter we are going to be adding a draw order property to the Component class. This number will modify the order in which the GameScreen will draw its components. We will need to modify Component, GameScreen, ComponentCollection, and create a custom enumerator called ComponentEnumerator that will allow us to loop over the components by their draw order.
The first thing we are going to do is add an int property called drawOrder to the Component class. We will also create a public version of this called DrawOrder that fires an event called DrawOrderChanged when the value changes, which other objects can ‘hook’ to be notified when the draw order changes. For example, ComponentCollection needs to know about this so it can update the order it returns componennts in while drawing. Here is the code for the DrawOrder property and DrawOrderChanged, and the ComponentDrawOrderChangedEventArgs and ComponentDrawOrderChangedEventHandler. The latter two go outside Component somewhere, while the first two go inside Component.
// The draw order of the component. Lower values draw first
int drawOrder = 1;
// Draw order changed event
public event ComponentDrawOrderChangedEventHandler DrawOrderChanged;
// Public draw order. If the value is changed, we fire the draw
// order change event
public int DrawOrder
{
get { return drawOrder;}
set
{
// Save a copy of the old value and set the new one
int last = drawOrder;
drawOrder = value;
// Fire DrawOrderChanged
if (DrawOrderChanged != null)
DrawOrderChanged(this,
new ComponentDrawOrderChangedEventArgs(
this, last, this.Parent.Components));
}
}
// Event arguments for draw order change on a component
public class ComponentDrawOrderChangedEventArgs : EventArgs
{
// Component that was modified
public Component Component;
// The old draw order
public int LastDrawOrder;
// The collection that owns the component
public ComponentCollection ParentCollection;
public ComponentDrawOrderChangedEventArgs(Component Component,
int LastDrawOrder, ComponentCollection ParentCollection)
{
this.Component = Component;
this.LastDrawOrder = LastDrawOrder;
this.ParentCollection = ParentCollection;
}
}
// Event handler for draw order change on a component
public delegate void ComponentDrawOrderChangedEventHandler(
object sender, ComponentDrawOrderChangedEventArgs e);
Now we are going to make the ComponentEnumerator. This class is in charge of telling a loop what order to loop through objects in. For example, we want to draw in an order that is not neccessarily to the same as we would update. So, we will make a custom enumerator and have ComponentCollection return when drawing, ie: ‘foreach(Component component in Components.InDrawOrder)’. This enumerator takes a list of components, and a list of ints. The second list determines what order to return components in, as each number in the list refers to an index in the component list. Here’s the code:
using System.Collections;
using System.Collections.Generic;
namespace Innovation
{
public class ComponentEnumerator : IEnumerator
{
// The current position
int position = -1;
// The collection we are enumerating
ComponentCollection collection;
// The order in which to return items from 'collection'
List<int> ordered = new List<int>();
// The current item, which is the item who's index is
// at the current position in the order list
public object Current
{
get { return collection[ordered[position]]; }
}
// Constructor sets the local component list and order
public ComponentEnumerator(ComponentCollection Collection,
List<int> Order)
{
this.collection = Collection;
this.ordered = Order;
}
// Moves to the next item in the list
public bool MoveNext()
{
position++;
// If we have reached the end of the list, stop
// enumerating
if (position == ordered.Count)
return false;
// Otherwise keep going
return true;
}
public IEnumerator GetEnumerator()
{
return this;
}
// Resets to the beginning of the list
public void Reset()
{
position = -1;
}
}
}
Next we need to set up ComponentCollection to use this enumerator. There are a number of changes so here is the entire code with all the changes:
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Innovation
{
// A custom collection for managing components in a GameScreen
public class ComponentCollection : Collection<Component>
{
// The GameScreen to manage components for
GameScreen owner;
// The list containing each component's index in the
// component list, in the order we want them to draw
List<int> inDrawOrder = new List<int>();
// Constructor
public ComponentCollection(GameScreen Owner)
{
owner = Owner;
}
// Override InsertItem so we can set the parent of the
// component to the owner and manage the DrawOrder
protected override void InsertItem(int index, Component item)
{
// Remove component from it's parent's list
if (item.Parent != null && item.Parent != owner)
item.Parent.Components.Remove(item);
// Set the new parent
item.Parent = owner;
// Tell what to do when the item's draw order changes
item.DrawOrderChanged += new ComponentDrawOrderChangedEventHandler(ComponentDrawOrderChangeEventHandler);
base.InsertItem(index, item);
// Update its position in the draw order list
UpdateDrawPosition(item);
}
// Draw order changed event handler
void ComponentDrawOrderChangeEventHandler(object sender, ComponentDrawOrderChangedEventArgs e)
{
// We simply update the component's position using the
// existing method
UpdateDrawPosition(e.Component);
}
// Updates the position of the component in the draw order list
void UpdateDrawPosition(Component Component)
{
// Save the draw order and index location in the component list
int ord = Component.DrawOrder;
int loc = Items.IndexOf(Component);
// Remove the index from the in order list
if (inDrawOrder.Contains(loc))
inDrawOrder.Remove(loc);
// Create our index variable
int i = 0;
// Search through the ordered list until we find a component of
// lesser or equal draw order value
if (ord > 0)
{
while (i < inDrawOrder.Count)
// If the current item's draw order is greator or
// equal to the one we are working with...
if (Items[inDrawOrder[i]].DrawOrder >= ord)
{
// If it is greator, decrement it so it is
// above the component we are moving's draw order...
if (Items[inDrawOrder[i]].DrawOrder > ord)
i--;
// And stop looping
break;
}
// Otherwise, keep going (until we reach the end of the
// list)
else
i++;
}
// Insert the location of the component in the component list
// into the ordered list
inDrawOrder.Insert(i, Items.IndexOf(Component));
}
// Tells what enumerator to use when we want to loop through
// components by draw order
public ComponentEnumerator InDrawOrder
{
get { return new ComponentEnumerator(this, inDrawOrder); }
}
// Override RemoveItem so we can set the parent of
// the component to null (no parent)
protected override void RemoveItem(int index)
{
Items[index].Parent = null;
// Unhook the draw order change event
Items[index].DrawOrderChanged -= ComponentDrawOrderChangeEventHandler;
// Remove the component from the collection
base.RemoveItem(index);
// Rebuild inDrawOrder
inDrawOrder.Clear();
foreach (Component component in Items)
UpdateDrawPosition(component);
}
}
}
Finally, we will change GameScreen to use the new enumerator. Change this line in the draw method:
foreach (Component component in Components)
to this:
foreach (Component component in Components.InDrawOrder)
Now, we can test this out. If we create a new ClearScreen in the LoadContent method after we create our actor and run the game, we should see a red screen.
ClearScreen clr = new ClearScreen();
This is because the ClearScreen is drawing after the actor, overwriting anything it drew. But, if we tell the actor to draw after the ClearScreen, only the background will be red because the actor is drawing over it.
ClearScreen clr = new ClearScreen(); actor.DrawOrder = 2;
That’s all for this one, next up we’ll be adding physics to our engine!
Download the Code for this Chapter
Back to Game Engine Tutorial Series
« XNA Game Engine Tutorial Series #3 – Utilities, Components, Camera, Actor XNA 3.0 Released »



Hey Sean. I just would like to thank u for this great tutorials .. They are incedible usefull and understandable
Can´t wait for the next one.
floAr
I’ve been looking for stuff like this! Keep them coming!!!
Excellent set of tutorials, Sean! Your documentation is thorough and very comprehensible. I look forward to your next one.
Hi! nice tutorial
I wanted to ask-
why is the need for an event to fire in case of a DrawOrder change?
In this case, cant i simply update the ComponentCollection of the specific GameScreen to keep it in order? Why other components need to know about this.. ?
Lior
Hey Sean,
Again, another homerun with your tutorials.
I do have another question. I had to make the following change in order to reproduce the test above (ClearScreen drawing over Actor). Let me know your thoughts. With the code above the InDrawOrder list would always inserted the newest component into position zero.
if (Items[inDrawOrder[i]].DrawOrder > ord)
{
i–;
break;
}
else
i++;
I had to do the same as monkeyboy =/
> why is the need for an event to fire in case of a DrawOrder change?
There’s not, really. You could just as easily create a Comparison delegate and sort the temporary lists by the draw order.
I am not expert but in both my typed out code, and your project file you cannot get the result you describe.
It is something to do with the way the drawOrder is used.
I am not sure on the full cause yet, but I am looking into, without a hack fix, which can be done but is not pretty.
Chris,
The problem you’re having is in line 71 of the ComponentCollection class above. Change the >= to just > and it should work for you.
This happens because unless you specify a draw order for each component they are all defaulted to 1. Since on line 71 it was greater than OR equal-to as monkeyboy stated it was not passing the if check on line 75 if they were equal, and breaking out immediately to the insert which would put it just before all components with the same DrawOrder.
I also changed line 75 to if(i > 0) because of problems with expicitly setting the DrawOrder of a Component to a non default value. Occasionally index ‘i’ would end up as a -1 which will crash on the Insert. This just makes sure that ‘i’ doesn’t go below 0 which is the very front of the Collection anyway.
Thanks again Sean for some great ideas.
it does not display the box just red back ground? why?
Not sure if this site is still active, but was wondering if anyone could explain line s 40 onwards in a bit more detail, i understand what its doing, just seems to be a complicated way of doing it.
having trouble understanding what i is keeping track of exactly so many indexes flying around at the moment these lines are confusing me
if (Items[inDrawOrder[i]].DrawOrder > ord)
What does
Items
inDrawOrder
i
represent in terms of the game. i know there varibles/lists
A word of warning: As stated above, the while loop in the UpdateDrawPosition method in the ComponentCollection class is wrong. To get it to work properly change it to this:
while (i ord)
break;
else
i++;
}
This will enable the InDrawOrder list to work correctly.
NOTE: If you are NOT explicitly setting the DrawOrder property of your components they are being assigned a default DrawOrder = 1, and thus they will be drawn in the order in which they are created (i.e. 1st created is 1st drawn), making the last component to be created appear at the ‘front’ of the screen (drawn on top of the other components)
Also, if you are NOT explicitly setting the DrawOrder property, and thus ALL your components have a DrawOrder = 1, then you can move any component in the collection to the back of InDrawOrder by simply saying:
component.DrawOrder = 1;
e.g. actor.DrawOrder = 1;
This effectively brings that component to the front of the screen, since it’s drawn last.
Edit: The code for the while loop in my previous comment didn’t come out right, so here it is again:
while (i < inDrawOrder.Count)
{
if (Items[inDrawOrder[i]].DrawOrder > ord)
break;
else
i++;
}