Program Structure

As we've covered in previouus lectures, putting all of your code into the main Game class is a really, really bad idea. The main game class should just be a container for all of the various game components. It should create all of the main classes, and can do some setup work (though really, each component should set itself up as much as possible), and then should just get out of the way -- on each update and draw, it should just make calls to the various update and draw methods of its contained components. Your main class should probably look something like the following:
namespace MyGameNamespace
{
    public class MyGameName : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager mGraphics;

        // Save components as instace variables

        public MyGameName()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            // Create all of your components
            //  Either add them to the Components of the superclass
        }

        protected override void Initialize()
        {
		    // If you need to do any initialization of your components, it can be done here	
            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Load content as necessary
            //    As much as possible, each component should load its own content
            //    Put calls in here to the approprate LoadContent methods of the 
            //    appropriate components
        }

        protected override void UnloadContent()
        {
            // Likely not to need this for your games
        }

        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
                
            //  Call update on each of your components
            //    (or let the system do it for you, if you added them to the superclass's Components
            //     collection)
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            //  Call update on each of your components
            //    (or let the system do it for you, if you added them to the superclass's Components
            //     collection)
 
            base.Draw(gameTime);
        }
    }
}

The key to notice here is that very little is happening in the main program -- each component is taking care of itself

Component Structure

What should be a component? As always, we should avoid the two extremes:

So how should we break our game into componets? Like any other software engineering project, we should look at how the components function. Each component should handle a single aspect of the gameplay, and be as independent as possible from the other components in the game. Some posibilities for components are:

Components != Classes

While Components will be implemented as classes, they should not be the only classes in your program! You will likely need classes for animation, enemies (perhaps with subclasses for different kinds of enemies), pojectiles, world elements (platforms, obsticles), and so on. A component represents a top-level functional chunk of your game. A class is used to define any object in your game.

Component Communication

The above structure is all well and good if the componets don't need to interact with each other, but that is usally not the case. You will want to design your components so that you limit communication, but you will not be able to remove it completely -- a game where enemies can not interact with the player in any way would not be a very interesting game! So, how should the componets communicate with each other? There are several models:

  1. Every component has a pointer to the containing game, and the game has access methods to get at each component. To communicate with another component, go through the game, get the appropriate component, call the appropriate method.
  2. Each component has a pointer to any other component that it needs to communicate with. To communicate with another component, use the appropriate pointer to get to that component. The pointers can be set up in the initialization of the game
  3. All communication goes through a centeral intermediary. This method works well if there is a single World class, that keeps track of all elements in the world. When the player (or AI) wants to move, it calls a method on the world to set the position (or velocity, or apply forces to) the object in the world. The world handles collisions, making the appropriate callback functions to elements that collide. The world owns the positions of each object (regardless of where that data is actually stored) Actions like "notify every element within a 10 unit distance of a certain point" (to handle explosins, grenades, etc) becomes much eaiser with this method

 

Singleton Design Pattern

If everyone is going to need access to a particular component, and there will only ever be one instance of that component, it might make sense to use a singleton design pattern:
    class SingletonClass
    {
        private static SingletonClass instance = null;
        private SingletonClass() 
        { 
        
        }
        public static SingletonClass GetInstance()
        {
            if (instance == null)
            {
                instance = new SingletonClass();
            }
            return instance;
        }

    }
Of course, you can make this as complicated as you like:
   class SingletonClass
    {
        public static SingletonClass GetInstance()
        {
            if (instance == null)
            {
                instance = new SingletonClass();
            }
            return instance;
        }

        public void Initialize()
        {
            initialized = true;
        }

        int SampleIntValue
        {
            get
            {
                CheckInitialized();
                return mIntValue;
            }
            set
            {
                CheckInitialized();
                mIntValue = value;
            }
        }

        private bool initialized;
        private int mIntValue;
        private void CheckInitialized()
        {
            if (!initialized)
                throw new InvalidOperationException();
        }

        private static SingletonClass instance = null;
        private SingletonClass() 
        { 
        
        }
    }

Using a World Component

One method of handling communication across componets is to have a world component that keeps track of all objects in the world. This component handles object intersection, as well as object location. If you are going to use a physics engine of some sort, you will need to follow a similiar pattern. There are many, many ways to do this properly, this is just one example:
namespace MyGameNamespace
{

    public enum Faction
    {
        Player,
        Enemy,
        Neutral,
    }

    [Flags]
    public enum CollisionFlags
    {
        None = 0,
        StaticObjects = 0x01,
        SameFaction = 0x02,
        DifferentFaction = 0x04,

        All = StaticObjects | SameFaction | DifferentFaction,
    }


    interface CollisionCallBackHandler
    {
        void HandleCollision(DynamicWorldObject o1, DynamicWorldObject o2);
    }


    interface DynamicWorldObject
    {
        // You'd want something more sopisticated than just an AABB bounding box
        // to handle collisions properly.
        Rectangle AABB();
        CollisionFlags CollisionFlags();
        Faction Faction();
        
        // Other methods common to dynamic objects 
    }


    class World
    {
        void AddObject(DynamicWorldObject o, CollisionCallBackHandler collisionCallBack) { }
        void RemoveObject(DynamicWorldObject o) { }

        void SetVelocity(DynamicWorldObject o) { }
        void GetPosition(DynamicWorldObject o) { }
        void GetVelocity(DynamicWorldObject o) { }
    }
}
On the Update method for the world, it would modify the positions of the objects based on their current velocity, handle any collisions based on the collision flags of the objects, and make any approriate callbacks if collisions occured. Given the above defintions, a collision of Object1 and Object2 would get two callbacks -- one the the collision handler for object1 (passing in Object1 and Object2), and one for the collision handler for object2 (which might be the same as object1) passing in object2 and object1.

 

Coding Conventions

Now that we've tamed the basic structure of our game, it's time to talk a bit about writing the actual code in a way that is extensible, maintainable, and easy to debug. Let's start with the basics:

Formatting & Naming

It may seem like a little thing, but consistent naming and formatting of your code will save you countless headaches down the road. It doesn't particually matter what coding standards you use (though some are certainly better than others!) as long as you pick a style and stick to it.

Instance variable access

You should always access instance variables in a class through getters / setters (the C# Properties are just syntactic sugar for getters and setters). You can change the underlying data representation easily (without changing every other piece of code that uses the class), and you can also determine when a value is being changed -- slap a breakpoint into the setter, and you can see who is modifying the value when. You don't need to look through the entire codebase (which will end up begin quite large for a substantial game) in order to see who is modifying the values of instance variables, and you don't need to deal data watchpoints

Functional Decomposition

Alas, there is no algorithmn for decomposing your code into functions. There are some good rules of thumb, however:

Documentation

Commenting you code -- how much is enough? How much is too much? To some extent, this is an art rather than a science, but there are good guidelines