Home | Upgrading to XNA 2.0| Forum



 

Building the Base Code from Scratch
This article is intended for readers of The Microsoft XNA Game Studio Creator's Guide because it references pages within the book. We recommend reading this article only after you have read and have a fairly good understanding of the chapters about primtives, shaders, textures, vectors, matrices, and building a camera.

Introduction
If you purchased the Microsoft XNA Game Studio Creator's Guide, thank you for choosing our book. In addition to being a thorough introduction to 3D games programming, we hope you found that the book helped you code your own custom 3D game from scratch. Reader reviews across the web strongly support our claim that we have succeeded on these goals.

This article explains how to build the base code from scratch using the code from the book. This base code project can then be used to begin all examples discussed in the Microsoft XNA Game Studio Creator's Guide. The only time we don't use this base code is when we use GSE's built-in XNA Game Studio Express templates.

A fair amount of background is needed to understand the entire XNA 3D game framework. Some understanding of primitives, shaders, textures, input devices, vectors, and linear algebra is required. To ensure we do this properly in the book, we discuss all of these topics in a sequence which allows readers to get coding right away and to learn as they proceed with creating more advanced structures and effects. However, this demonstration does not follow this sequence. Consequently, this article is a little less user-friendly than the book. We are breaking this order so we can get to building the base code without explaining all of the chapters behind it. For background information on how all of the code works, please refer to the book.

This demonstration first jumps to Chapter 15: Building a Graphics Engine Camera to implement the viewer and input controls for the 3D world. It then shows how to add code from Chapter 7: Texturing Your Game World to enable textured surfaces. Finally, it adds code from Chapter 4: Shaders to explain how to add in shader code for drawing of non-textured primitive surfaces.

Step 1: Build the camera and enable input devices to control position and view.
Chapter 15 describes how to build a camera and how to control it with input devices. The camera is the main component of our game engine. By chapter 15, it assumes you have read about vectors and linear algebra in earlier chapters. If you need to brush up on input devices this is explained in more detail in chapter 21.

Follow the step by step example in chapter 15 to build the camera. This demonstration starts with the bare Windows Game template or the Xbox 360 Game template. If you want to take a shortcut, you can just start with the code from the solution that is provided with the download for the book. Either way works.

In the solution, we added a model windmill as a reference point for the viewer. The windmill has no impact at all on the base code. The windmill is an add-on to allow viewers to see changes to their view and position as they control it with mouse, keyboard, or game controller.

 
Step 2: Rename the GraphicsDevice object.
The Windows Game template and Xbox 360 Game templates have named their instance of the GraphicsDeviceManager object as graphics . In the book, we use the same object but it called named gfx . To fix this, an adjustment is required to your solution from chapter 15 that you assembled in step 1.

Replace all instances of graphics with gfx .

Step 3: Set the world size.
We use a constant value called BOUNDARY to control the size of the ground, terrain, skybox, and to keep the viewer from running over the edge of the world. Since we use it so much we included it with the base code. This value should be added to your new project so it can be used as needed in the chapter examples:

// Add this declaration to the top of the game class to define the world size.
const float BOUNDARY = 16.0f;

Step 4: Disable culling.
Culling is used for drawing efficiency to only display the front face of a surface. The default culling setting looks odd in our 3D world because it makes the back surfaces of primitive surfaces invisible. For this reason we disable culling in our project:

// Add this to Initialize() to disable culling as soon as the program begins
gfx.GraphicsDevice.RenderState.CullMode = CullMode.None; // see both sides

Step 5: Enable textured surfaces with a custom shader.
The discussion behind the shader code used for texturing surfaces and the means for implementing textures from your XNA code is continued in Chapter 7: Texturing Your Game World. The initial shader discussion is in chapter 4. Since we use the texture shader so much we added it to the base code.

Add the shader code from chapter 7 that is presented on page 96 to the midpoint of page 97 to a file named TextureShader.fx . Create a folder named Shaders in the Solution Explorer for your project. Add the TextureShader.fx file to this folder. To do this, right-click your project name in Solution Explorer and choose New Folder. When prompted name it Shaders . Then, drag and drop your TextureShader.fx file onto this folder to reference it from your project.

Step 6: Reference the texture shader.
An Effect object is required to reference this new shader. Also, two EffectParamater objects are needed so you can set global variables in your shader from your XNA code. These objects are explained and are added in other sections of the book however, to keep the naming in line with the base code, add these objects:

// Add these declarations to the top of the game class
private Effect mfxTex;
private EffectParameter mfxTex_WVP; // w*v*p matrix
private EffectParameter mfxTexture;      // texture

Step 7: Initialize the texture shader object and parameters.
The following code loads your shader from the Shaders folder. It then creates references to the global variables, fx_WVP and fx_Texture, which can be used to set the WVP matrix and texture variable that is applied in the shader. Once again these objects are explained and added in several sections in the book. To keep this simple and to match the naming with the book add these lines:

 
// Add to Initialize() to load your shader and reference it properly at program start-up
mfxTex = content.Load<Effect>(@"Shaders\TextureShader");
mfxTex_WVP = mfxTex.Parameters["fx_WVP"];
mfxTexture = mfxTex.Parameters["fx_Texture"];
mfxTex.CommitChanges();
 

Step 8: Enable drawing with this new texture shader.
Code is needed inside the Draw() method to reference the texture shader when drawing a surface that uses this texturing method.

// place this code inside Draw() just before base.Draw()
mfxTex.Begin();
mfxTex.Techniques[0].Passes[0].Begin();
 
mfxTex.Techniques[0].Passes[0].End();
mfxTex.End();

Step 9: Draw a textured surface
You now have the foundation needed to draw textured surfaces.

Add the code from the demonstration that is discussed in Chapter 7: Texturing Your Game World found on pages 98 to 103. This demonstration is called Texture Example, Part A: Opaque Textures .
 
The instructions that call draw_surface() need to be placed between the begin and end statements for the shader referenced by mfxTex in the Draw() method.

You will also need to add an Images folder to the project in Solution Explorer. You can then use this folder to store and reference your images that are used in the chapter 7 demonstration.

You can test your code now. You camera should work and you should be able to view the textured surfaces as you move and re-position your camera.

Step 10: Add a VertexDeclaration Object to store the VertexPositionColor format
Shaders are introduced in chapter 4. One of the first shaders described is used to draw a primitive surface that is created with position and color elements. A VertexDeclaration object is required to store the vertex format. This will be used later to set the graphics device so it can correctly draw an object with this format. To set up this declaration add the following code at the top of the game class:

private VertexDeclaration mVertPosColor;

To follow through, initialize the mVertPosColor object when the program begins. This can be done by placing the initialization statement in the Initialize() method.

mVertPosColor = new VertexDeclaration(gfx.GraphicsDevice,
VertexPositionColor.VertexElements);

Step 11: Add and implement a shader for drawing basic primitive surfaces
The code needed to draw a primitive surface which stores color and position with a custom shader is presented between page 51 to page 55.

// Add in the code from the Basic XNA Shader Example which is found on page 51 to
// page 55. However, in the last step on page 55, do not replace the entire Draw()
// method. We need to keep the code that you have already added there. To enable
// drawing of basic primitive surfaces with position and color elements, this addition to
// the Draw() method is required instead:
 
// begin using shader - IntroShader.fx
mfxEffect.Begin();
mfxEffect.Techniques[0].Passes[0].Begin();
 
// draw objects
drawRectangle();
 
// stop using shader - IntroShader.fx
mfxEffect.Techniques[0].Passes[0].End();
mfxEffect.End();

If you run the code now, you will actually see a fully functional base code structure. You should be able to view and move through your world in addition to being able to draw primitive and textured surfaces with custom shaders. It will look a bit odd because there are some extra surfaces, but everything you need is now in your project. All you really need to do now is delete the items you don't want and rename some of the objects to match the base code names.

Step 12: Rename objects or switch assets to match the base code objects and assets.
The last changes you make are purely cosmetic. Some renaming tasks must be performed to ensure the object names in your current project match the object names in the base code for the book. As you read through these last tasks I think you will agree they are trivial. (When renaming, I am sure most of you know to use the Find and Replace dialog that is presented when pressing ctrl+H but I am mentioning it here in case you don't. I strongly recommend using the match case and match whole word options if you don't use these already.).

  • All instances of mfxEffect need to be renamed to mfx .
  • All instances of mfxEffectWVP need to be renamed to worldViewProjParam
  • All instances of mVertPosTexColor1 must be renamed to mVertPosTexColor
  • In the shader folder rename IntroShader.fx file to BasicShader.fx
  • To reflect the shader name change, inside Initialize()
  • Replace:
    mfxEffect = content.Load<Effect>(@"shaders\IntroShader");
    with:
    mfx = content.Load< Effect >( @"shaders\BasicShader" );
  • Rename all instances of mVert to mVertGround.
  • Rename all instances of draw_surface() to draw_ground()
  • Rename all instances of init_surface() with init_ground()
  • Rename all instances of mTexGround to mTexGrass.
  • In LoadGraphicsContent() rename ground to grass.
  • Add the grass.jpg texture to the Images folder.
  • In the Draw() method, delete the three calls to draw surfaces that don't appear in the base code.
  • To position the ground surface properly, inside draw_ground()
  • Replace:
    matTransl = Matrix.CreateTranslation(0.0f, -0.9f, 10.0f);
    with:
    matTransl = Matrix .CreateTranslation(0.0f, -0.9f, 0.0f);
  • Then, remove all unwanted transformations by replacing:
    mMatWorld = matIdentity * matScale * matXrot * matYrot * matTransl;
    with:
    mMatWorld = matIdentity * matTransl;
  • You can also add tiling to repeat the grass texture inside init_ground() by replacing all instances where either uv.X = 1.0 or uv.Y = 1.0 with uv.X = 10.0 and uv.Y = 10 respectively.

That's it! You're base code is ready to use for all examples in the book. When you run the project, it will look and function exactly like the original base code project.