Well, lets dive right in to the deep end, shall we? In this article we will be initializing DirectX. Actually, we will be initializing our Direct3D device. The initialization of our Direct3D device will take place entirely in a new Renderer class. This article will also be introducing our engine class, BattleEngine.
At this point, we still have a fairly simple design. When this article is done, our general class architecture will look as follows:

One of the first things you might notice is the Instance attribute. Since we only want one instance of the BattleEngine to be created at any time, we will be using the Singleton Pattern. The Singleton Pattern is a really good way to ensure that only one instance of a class exists at any time. As you can see, we only really have one subsystem at the moment: the Renderer. The Renderer class is our class that will encapsulate most access to our rendering system. We won’t be totally encapsulating access to our Render most for learning experiences. This article should teach us how to develop a basic 2d game. We will not be worrying about building a cross-platform game, and hence, will not worry about creating a “virtual system” to hide away all DirectX access (making it easier to plug in a different system like OpenGL).
Let’s go ahead and dive right into the code. The renderer is where we will actually initialize our Direct3d device. We will plan on rendering the game in windowed mode when we are debugging to make debugging easier. This is because debugging in Full Screen mode can be extremely difficult unless you are running a multi-monitor solution. When in Debug mode, it is easier to set breakpoints and step through the code while still allowing the program to be run after the debugging is finished. We will only run in Full Screen mode when we are running a Release build.
The constructor of the Renderer class is where we will initialize our device. The first thing that we want to do is to create our present parameters depending on whether we are in debug or release mode.
private System.Windows.Forms.Control _targetControl;
// no property accessor
private Device _device;
public Device Device
{
get { return _device; }
}
public Renderer(System.Windows.Forms.Control targetControl)
{
_targetControl = targetControl;
// presentation parameters will be different depending on whether we are
// in Debug mode or not (Windowed in Debug, Full Screen in Release)
PresentParameters presentParams = new PresentParameters();
#if DEBUG
presentParams.Windowed = true;
#else
presentParams.Windowed = false;
presentParams.DeviceWindow = this.targetControl;
presentParams.BackBufferFormat = Format.X8R8G8B8;
presentParams.BackBufferHeight = this.targetControl.Size.Height;
presentParams.BackBufferWidth = this.targetControl.Size.Width;
presentParams.PresentationInterval = PresentInterval.Default;
#endif
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.AutoDepthStencilFormat = DepthFormat.D16;
presentParams.EnableAutoDepthStencil = true;
The next thing that we need to do is to create our creation flags. For some of the creation flags, we will need to check to make sure that our device supports the feature we will be creating the device with. This is done by using the various Support* attributes in the device’s DeviceCaps structure.
// store our default adapter
int adapterOrdinal = Manager.Adapters.Default.Adapter;
// get our device capabilities so we can check
Caps caps = Manager.GetDeviceCaps(adapterOrdinal, DeviceType.Hardware);
CreateFlags createFlags;
if (caps.DeviceCaps.SupportsHardwareTransformAndLight)
createFlags = CreateFlags.HardwareVertexProcessing;
else
createFlags = CreateFlags.SoftwareVertexProcessing;
if (caps.DeviceCaps.SupportsPureDevice)
createFlags |= CreateFlags.PureDevice;
Now, there is only one thing left for us to do. Now that we have gathered all information we need, we will create our device. One thing to notice is that we are creating the device as well as using the DeviceReset event. Trapping this event will allow us to automatically re-create our various device-dependant elements.
// create our device
_device = new Device(adapterOrdinal, DeviceType.Hardware, _targetControl,
createFlags, presentParams);
_device.DeviceReset += new EventHandler(this.OnDeviceReset);
OnDeviceReset(_device, null);
}
Before moving on the OnDeviceReset method, I would like to explain how we are setting up the camera. Since this is a two dimensional game, I want to create a static camera that will be pointing directly at the middle of the positive quadrant. So, if we have the following setup of a two dimensional grid:
+y
|//////////////////
|//////////////////
|//////////////////
|//////////////////
|//////////////////
-x ------------------ z ----------------- +x
|
|
|
|
|
-y
The shaded quadrant is the quadrant that out game will take place in. By dealing with all positive coordinates, and having the center of the camera (and the screen) directly in the center of the positive quadrant, our code should be significantly more intuitive to read. With that explained, let’s look at the creation of our various device-dependant elements:
public void OnDeviceReset(object sender, EventArgs e)
{
Device newDevice = (Device)sender;
// set device states
newDevice.RenderState.Lighting = false;
// get camera vectors
float width = (float)_targetControl.Size.Width;
float height = (float)_targetControl.Size.Height;
float centerX = width / 2.0f;
float centerY = height / 2.0f;
Vector3 cameraPosition = new Vector3(centerX, centerY, -5.0f);
Vector3 cameraTarget = new Vector3(centerX, centerY, 0.0f);
// create our transforms
newDevice.Transform.View = Matrix.LookAtLH(cameraPosition, cameraTarget,
new Vector3(0.0f, 1.0f, 0.0f));
newDevice.Transform.Projection = Matrix.OrthoLH(width, height, 1.0f, 10.0f);
}
As of now, there are only two more methods left to define in the Renderer class: BeginScene( ) and EndScene( ). Both methods are relatively self explanatory.
public void BeginScene()
{
_device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, System.Drawing.Color.Black, 1.0f, 0);
_device.BeginScene();
}
public void EndScene()
{
_device.EndScene();
_device.Present();
}
Now that our Renderer is initialized and setup, we need to code up our BattleEngine class. The first thing we need to is the Singleton Pattern implementation mentioned above. Along with the Singleton implementation, we also have our various attributes and properties used to access our subsystems and various engine data.
public sealed class BattleEngine
{
// Singleton implementation
private BattleEngine() { }
public static readonly BattleEngine Instance = new BattleEngine();
// Attributes/Properties
private System.Windows.Forms.Control _targetControl;
public System.Windows.Forms.Control TargetControl
{
get { return _targetControl; }
}
private Renderer _renderer;
public Renderer Renderer
{
get { return _renderer; }
}
Next we need to initialize our engine. Initializing our engine at this point will mostly consist of initializing our various subsystems (currently only the Renderer).
public void Initialize(System.Windows.Forms.Control targetControl)
{
_targetControl = targetControl;
// Initialize Subsystems
_renderer = new Renderer(_targetControl);
}
That was pretty easy I must say! The only thing left in the current engine is the Frame function. All we currently do in the Frame function is to call the Render function (since we have no subsystems to update). The Render function just cals the BeginScene( ) and EndScene( ) functions for now since we don’t have any game objects to render.
public void Frame()
{
// TODO: Update Subsystems Here
Render();
}
private void Render()
{
_renderer.BeginScene();
// render game objects here
_renderer.EndScene();
}
}
That is it for our BattleEngine class for now. All that is left for this article is to hook our BattleForm into our BattleEngine. The only two hooks that are needed in the form is to initialize our engine and to update our game in the OnPaint( ) method. Below are the new implementations of the functions that we ironed out in the last article for the BattleForm class:
public void Initialize()
{
BattleEngine.Instance.Initialize(this);
}
protected override void OnPaint(PaintEventArgs e)
{
BattleEngine.Instance.Frame();
// IMPORTANT: Make sure that we are called again as soon as we are drawn
this.Invalidate();
}
Before we run our application, let’s go ahead and add an ability to exit the application. We will be doing that by simply overriding the OnKeyDown event on the BattleForm class and checking to see if the user has pressed “Escape”.
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if ((int)(byte)e.KeyCode == (int)Keys.Escape)
this.Close();
}
Well, that’s it for this article folks. Stay tuned for next time where we will create our input system that will drive our game. ‘Til next time :~).