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();
Red Screen

Red Screen

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;
Actor with red background

Actor with red background

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

« »