Game Engine Tutorial Part III, Chapter 2 – GameScreen

Add a new class to your engine’s project, and this time call it “GameScreen”. Once again we can remove some of the “using” statements, until we are left with the following.

using System;
using System.Collections.Generic;

namespace InnovationEngine
{
    public class GameScreen
    {
    }
}

As GameScreen is in charge of managing a set of components, the first thing we need to add is a list of components.

List<Component> components = new List<Component>();

The “<” and “>” and the type between them signify the type of list we want to create. As the List class is designed to work with any type of object, we must specify what type of object we want this list to work with. This is called a “generic” argument, and you will find that many classes use them; in fact some of our classes will also use them later on.

We should probably start by providing a way for components to be added to the GameScreen. The method below does just that. You will note that it first checks if the component is already in the list, as we will run into issues if a component is added more than once. If the component is a new one, it will add it to the list and also set the GameScreen as the component’s “Parent”. We haven’t added this property to the Component class yet, but we will in a moment.

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

We also want to provide a way for external code to access the list of components. We will do this similarly to the way you access items in an array, using the [] and index, except here we will use a string as the index instead of an integer.

// Allow for components to be retrieved with the [] index, ie:
// Component c = gameScreenInstance["Component1"];
public Component this[string Name]
{
    get
    {
        foreach (Component component in components)
            if (component.Name == Name)
                return component;

        return null;
    }
}

We also want to provide a way to remove components from the screen. We will actually be providing two functions that do this. One takes the component itself as an argument, while the other takes the name of the component. The second function actually just retrieves the component using the index functionality we just added, then calls the second function using that component as an argument.

public void RemoveComponent(string Name)
{
    Component c = this[Name];
    RemoveComponent(c);
}
public void RemoveComponent(Component Component)
{
    if (Component != null && components.Contains(Component))
    {
        components.Remove(Component);
        Component.Parent = null;
    }
}

The last two functions we need to provide are the Update and Draw functions. These two functions simply loop through the list of components, and call Update and Draw on each of them. There is one caveat here, though, which is that components may be added or removed from the screen during this update. What happens if the list of components is modified while we are looping through it? Well, the list will through an exception, and the game will crash. To avoid this problem we first copy the list before iterating through it in the Update function. You will note that we once again made these functions “virtual”, so that classes that build on top of the GameScreen will be able to add their own code to them.

public virtual void Update()
{
    // Copy the list of components so the game won't crash if the original
    // is modified while updating
    List<Component> updating = new List<Component>();

    foreach (Component c in components)
        updating.Add(c);

    foreach (Component c in updating)
        c.Update();
}
public virtual void Draw()
{
    foreach (Component c in components)
        c.Draw();
}

To finish this all off, we need to add the Parent property mensioned earlier to the Component class. Notice that there are some extra checks in the “set” portion of the property to make sure that the parent variable is only changed if it is not set to the new value already. This avoids an infinite loop: as we want to be able to either set the parent on the component directly, or use the AddComponent method on the GameScreen, we need to always be sure to notify either the GameScreen if a component has set it as its parent, or the Component if it has been added to a GameScreen. However, notifying one of them will cause them to notify the other again, and they will continuously let eachother know about their new affiliation until the game runs out of memory and crashes. To avoid this, we make sure that we are not notifying the parent GameScreen unless there is actually a change in parents happening.

GameScreen parent;

public GameScreen Parent
{
    get { return parent; }
    set
    {
        if (parent == value)
            return;

        if (parent != null)
            parent.RemoveComponent(this);

        parent = value;

        if (value != null)
            parent.AddComponent(this);
    }
}

Download the Code for this Chapter

12 Responses to “Game Engine Tutorial Part III, Chapter 2 – GameScreen” »

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

    [...] Game Engine Tutorial Part III, Chapter 2 – GameScreen [...]

  2. Comment by Mankle — October 24, 2009 @ 2:50 am

    Hey bro, the second part of code needs to be updated to this:

    List components = new List();

    In the sample code you have, the are < and >.

  3. Comment by Mankle — October 24, 2009 @ 2:51 am

    My apologies that utterly screwed up, but i’m sure you get the point…

  4. Comment by Sean — October 24, 2009 @ 2:53 am

    Right, thanks

  5. Comment by Robert — October 29, 2009 @ 1:23 am

    you need to specify the type though when using generics soare the “” requiered?

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

    Bug in GameScreen.Parent->set
    Example:
    GameScreen gs = …;
    gs.Parent = gs.Parent;

    Now gs’s parent doesn’t know gs is a child. The example is rediculous but it gets the point across. Since the first thing that happens is the component is removed from parent list. Then the value is checked to see if it has changed. Since the value’s are the same, the compent is never added back to the parent’s list.

  7. Comment by Sindow — November 30, 2009 @ 11:52 pm

    Is there a reason you can’t lock the component list using lock(components) instead of copying an entire new list?

  8. Comment by Sean — November 30, 2009 @ 11:55 pm

    Because we still want to be able to add and remove components to the list during update, but doing so directly would cause an exception.

  9. Comment by Shane — December 27, 2009 @ 6:29 pm

    Hey, I think I have found an issue that would be a nice little bug to track down later. If I am correct then this may save time later…

    See this chunk of code…do you see any problems with the logic?

    GameScreen parent;

    public GameScreen Parent
    {
    get { return parent; }
    set
    {
    if (parent != null)
    parent.RemoveComponent(this);

    if (parent != value)
    {
    parent = value;

    if (value != null)
    parent.AddComponent(this);
    }
    }
    }

    Basically, well I think so, it removes the component from the gamescreen parent if the parent is currently set. It then checks to see if we are trying to set the parent to the same parent again, if we don’t then we set the new parent value, and add the control to if it is not null.

    The problem with this is that if the parent is currently set, we remove the component from it, and then if we are trying to set the parent to the same parent value it stops there, so therefore the component is never set to a game screen again.

    I believe with this code that if you set the parent value to the same value the component is removed and never added to a game screen again (it is lost).

    The code should be…

    GameScreen parent;

    public GameScreen Parent
    {
    get { return parent; }
    set
    {
    if (parent != value)
    {
    if (parent != null)
    parent.RemoveComponent(this);

    parent = value;

    if (value != null)
    parent.AddComponent(this);
    }
    }
    }

    all at least something along those lines to ensure that the component is still in a gamescreen (or rather the component can access it’s game screen). I do hope this makes sence, an that I am right?

    Thanks for the greate tutorial(s)…Looking forward to the next ones :D

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

    Fixed

  11. Comment by tj — February 28, 2010 @ 3:41 pm

    when I typed in the code for this lesson, it says that I am getting alot of syntax errors, and I copied EXACTLY the code you typed, I even copied and pasted the code I downloaded, and it still showed errors, do I need to worry about that?

  12. Comment by tj — February 28, 2010 @ 4:00 pm

    my main problem is that in the code for the gamescreen, when it involves the
    ‘Parent.RemoveComponent(this);’

    and the:

    parent.AddComponent(this)

    I get an error message for the following:
    Error 1 The best overloaded method match for ‘GamenoviceEngine.GameScreen.RemoveComponent(string)’ has some invalid arguments line 77 column 25

    Error 2 Argument ’1′: cannot convert from ‘GamenoviceEngine.GameScreen’ to ‘string’ line 77 column 48

    Error 3 The best overloaded method match for ‘GamenoviceEngine.GameScreen.AddComponent(GamenoviceEngine.Component)’ has some invalid arguments line 82 column 25

    Error 4 Argument ’1′: cannot convert from ‘GamenoviceEngine.GameScreen’ to ‘GamenoviceEngine.Component’ line 82 column 45

RSS feed for comments on this post. TrackBack URI

Leave a comment