Game Engine Tutorial Part III, Chapter 1 – Component

The component class is pretty simple. It only needs to (for now) provide an Update function and a Draw function, and keep track of its name. The name needs to remain unique, meaning that it must always be the only component that has that name. This is so that later on when we get into more complicated interactions with the scene, like in the editor or scripting language, we will be able to easily identify components by name.

Start by adding a new class to the engine library’s project, by right clicking on the node in the solution explorer (“InnovationEngine”), and clicking “Class” under “Add”. Give it the name “Component” in the popup window, then hit OK. You will now be generated a file that will store the code for this class. At this point, you can also delete the “Class1.cs” file that was created when the project was. Now we’ll modify some of the “using” statements, so that the code looks like this:

using System;
using System.Collections.Generic;

namespace InnovationEngine
{
    public class Component
    {
    }
}

We’ll now add the constructor to this class, leaving it blank for now. The constructor is like a special function that is called when the class is first instantiated (when a new copy, or “instance”, of the class is created). The constructor is generally used to set up the class for use before any other functions are called. The code for a constructor is simple (you can also have this generated for you by typing “ctor” followed by quickly pressing “Tab” twice:

public Component()
{
}

Now we need to add the two core functions of the Component class: Update and Draw. We will define these as “virtual” functions, meaning that the components derived from this class can “override” their functionality. This will allow new components built off of this base class to insert their own functionality for updating and drawing themselves.

public virtual void Update()
{
}

public virtual void Draw()
{
}

The last thing we need to do for now is store the component’s name. We will have a private variable “name” with a public property of the same name. This is good design practice; generally you don’t want to make variables that belong to the class public for anyone to modify. You’ll see why in the “set” part of this property: we can check the value that the user is trying to set as the name. If they try to set it to “null” or if they provide an empty string, we can complain and throw an exception, basically pointing out that an error condition has arisen.

string name;

public string Name
{
    get { return name; }
    set
    {
        // Make sure we have a valid name before allowing it to be
        // changed
        if (string.IsNullOrEmpty(value))
            throw new Exception("Component name must not be null "
                + "and be greater than 0 characters");
        else
            name = value;
    }
}

The last thing we will do is add a private function, meaning that only the Component class will know about it, that generates a unique name when the component is first created. It will do this simply by keeping track of the number of components of each possible type that have been created. Every time a new component is created, it will check the type and increment the number that it knows have been created. The name it generates will simply be the type name with the number of that type created after it. For example, if we just created a bunch of “Component”’s they would end up defaulting to the names “Component1”, “Component2”, “Component3”, etc. Later on, however, as we create new types of components, we could end up with “Terrain1”, “Actor3”, “Model5”, etc.

// Keep track of the number of each type of component that have been
// created, so we can generate a unique name for each component
static Dictionary<Type, int> componentTypeCounts = new Dictionary<Type, int>();

// Generate a unique name for the component simply using the type name
// and the number of that type that have been created
private void generateUniqueName()
{
    Type t = this.GetType();

    if (!componentTypeCounts.ContainsKey(t))
        componentTypeCounts.Add(t, 0);

    componentTypeCounts[t]++;

    this.name = t.Name + componentTypeCounts[t];
}

Finally, we need to call this function in the constructor, so the name will be generated immediately when the component is created. The constructor will now look like this:

public Component()
{
    generateUniqueName();
}

Download the Code for this Chapter

8 Responses to “Game Engine Tutorial Part III, Chapter 1 – Component” »

  1. Pingback by Innovation Engine Roadmap 2009-2010 | Innovative Games — October 20, 2009 @ 7:35 am

    [...] Game Engine Tutorial Part III – Component [...]

  2. Comment by Chris Harshman — October 25, 2009 @ 7:56 pm

    As a suggestion component names should be unique.

  3. Comment by Chris Harshman — October 25, 2009 @ 7:57 pm

    whoops, I spoke before I read.

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

    Hey quick question you guys dose this mean that the XNA framework is going to update each one of our objects, fr us automatically? If, so where do we perform collision checks as well as sorting for our render states?

  5. Comment by tj — February 28, 2010 @ 9:59 am

    Hey, for creating a new class for the component, I am running XNA 3.0, and it gives me a menu of stuff to use, I went with the GameComponent, I am wondering what is the correct class category

  6. Comment by tj — February 28, 2010 @ 11:17 am

    Is the generateUniqueName a proper command, beecause on my computer it counts it as a syntax error

  7. Comment by Apox — April 23, 2011 @ 6:44 pm

    It’s not a command, you are creating that function so technically you could call it whatever you want. What is the syntax error? you might of done something else wrongwhen typing out that function.

  8. Comment by danyo — April 1, 2012 @ 6:09 pm

    I don’t understand at all, i look at the file you have created and that is downloadable – i look at your instructions and my own file that i’ve created and the layouts are completely different. This is explained poorly.

RSS feed for comments on this post. TrackBack URI

Leave a comment