Search Forum
(57415 Postings)
Search Site/Articles

Archived Articles
712 Articles

C# Books
C# Consultants
What Is C#?
Download Compiler
Code Archive
Archived Articles
Advertise
Contribute
C# Jobs
Beginners Tutorial
C# Contractors
C# Consulting
Links
C# Manual
Contact Us
Legal

GoDiagram for .NET from Northwoods Software www.nwoods.com


              
Printable Version

Breakout 3D
By Mathias Edman

The Game

For educational purpose only

Ok, I'm sorry for not having the imagination to come up with something on my own but I really love those classic games. I really miss those days when everything was simple and in two directions. But now it's different, people today must have everything in 3d. So here it is, my version of breakout.

The game resolution is 1024x768 and the objects are many and rather complex, therefore the game needs quite good hardware to run properly. I designed the game to run 50 f/s.

Known bugs :
At some hardware/driver configurations bricks are not present.

General Information :
To play this game you will need to install .NET framework and managed DirectX 9.0(mdxredist.msi).

To compile this game you will need to install .NET framework and DirectX 9.0 SDK(dx9sdk.exe). If it won't compile include the resource files (.dll) that is needed from the file DirectX.cab and put them in the folder Microsoft.NET/framework/vxxxx/ in under Windows.

The resources :
The sound effects are freeware from http://www.flashkit.com/soundfx/
The songs are for you to copy to folder Audio/Mp3/
The Textures are from http://www.redfieldplugins.com/Textures.htm
The DirectX objects are made with Maya 4.0
The backgrounds are freeware from http://www.mediabuilder.com/  
Description

The first thing I do when I'm programming something that I haven't worked with before is of course to gather information. I found the main things I needed for my project in the samples given in the SDK. Microsoft didn't make this any easy reading though.

I think that it's really important to fully understand every piece of code you write. The people that doesn't agree with me and just copy code from other projects will do later on, when they try to add/change/remove something and they don't know squat about how things works.

I would be proud to say that I now know everything about the sample code that I read from Microsoft SDK, but guess what, I don't. It seems that if that was my goal I would probably still be reading it. Because of this there is unfortunately some code that I do not fully understand, but I managed to get the crucial parts out of it and made some classes to help me in my programming. Classes that make programming easier is a good thing to do when you learning something new.

The classes that are named DirectX are not from Microsoft. They are the classes that help me with the structure and the many different DirectX functions. The best things about these classes are that they are made for one purpose and of course that they are recyclable.

As you can see from the diagram all the action leads to the main class Breakout3d. This class got a little to big and difficult to understand. Sorry for that but it's quite a big game.

Game Classes

I will not include or comment any code from the actual game (game classes) here. It's for you to read by your self. But don't let that stop you. For those who consider themselves to be intermediate programmers the reading should be easy as pie :).

The main class goes like this :
Timer -> FrameMove -> RenderScene

This is a common structure. The objects and camera are moved in the function FrameMove() and are rendered in RenderScene(). Together with different states makes this a standard way to program. This type of programming is also used i.e. real-time programming of state machines.

The code written in this class together with the different classes for the game objects is the core. It tells us everything about the game, but it doesn't tell us anything about how the game really is communicating with its surrounding environment. The DirectXClasses below gives us the necessary information.

DirectXBackground

vertexBackground = new VertexBuffer( typeof( CustomVertex.TransformedColoredTextured ), 4, device, Usage.WriteOnly, CustomVertex.TransformedColoredTextured.Format, Pool.Default );

CustomVertex.TransformedColoredTextured[] v = new
CustomVertex.TransformedColoredTextured[ 4 ];

for(int i = 0; i < 4; i++)
{
v[ i ].SetPosition(new Vector4( position.X, position.Y, position.Z, 1.0f ));
v[ i ].Color = unchecked( ( int )0xffffffff );
}
v[0].Y = ( float )device.PresentationParameters.BackBufferHeight;
v[2].Y = ( float )device.PresentationParameters.BackBufferHeight;
v[2].X = ( float )device.PresentationParameters.BackBufferWidth;
v[3].X = ( float )device.PresentationParameters.BackBufferWidth;
v[0].Tu = 0.0f; v[0].Tv = 1.0f;
v[1].Tu = 0.0f; v[1].Tv = 0.0f;
v[2].Tu = 1.0f; v[2].Tv = 1.0f;
v[3].Tu = 1.0f; v[3].Tv = 0.0f;
vertexBackground.SetData(v, 0, 0 );
To make a background we need to establish four vertex points in the 3d world, these four vertexes forms a square where the background will be drawn.
The first thing we do here is to pick a reference. This is done in the for loop above where the vertexes are getting same positions. Then just move them where you want you're background to be placed. Last we call a function to set the data in the vertex buffer that is linked the directx3d device.

Remember that these functions do not exclusively need to be applied on backgrounds.

device.SetTexture( 0, textureBackground );
device.VertexFormat = CustomVertex.TransformedColoredTextured.Format;
device.SetStreamSource( 0, vertexBackground, 0 );
device.DrawPrimitives( PrimitiveType.TriangleStrip, 0, 2 );
This is the code to render the background. First we tell the directx3d device that we want to draw a texture. Then we tell the device which vertex format that it should use. Before we call the draw function we bind the vertex buffer to a data stream port (see the SDK documentation for more information).

DirectXCamera

Matrix view = Matrix.LookAtLH( cameraPosition, cameraDirection, cameraUpDirection );
device.SetTransform( TransformType.View, view );
Matrix projection = Matrix.PerspectiveFovLH( fFieldOfView, fAspectRatio, fNearPlane, fFarPlane ); 
device.SetTransform( TransformType.Projection, projection );
Every collection of information in a 3d world is described in matrices. A matrix is a bunch of numbers that describes something like shapes, functions or in this case information about a slice in a 3d world.

This code tells the device where we want to place our point of view. First make a matrix over the area you want to look at with the function LookAtLH () which builds a Left-Handed view matrix. Then tell the device that this is our view. The device now needs one last thing and that's a perspective. We inform the device about the perspective in the same way as for the view. The function PerspectiveForLH() builds a left handed projection matrix with the given parameters. If you are programming in 2d you should use the function OrthoLH() instead.

DirectXMisc

Contains functions for finding files, show statistic etc.

DirectXFont

Mesh threeDText = Mesh.TextFromFont( device, textFont, text, fDeviation, fExtrusion);

The 3d font is just an ordinary mesh. The static function TextFromFont() builds the mesh. The render and move functions are the same as in the class DirectXObject.

DirectXLight

It's not much fun without lights

device.Lights[ lightNo ].Type = LightType.Point;
device.Lights[ lightNo ].Position= lightPosition;
device.Lights[ lightNo ].Attenuation1= fAttenuation;
device.Lights[ lightNo ].Diffuse= diffuseColor;
device.Lights[ lightNo ].Ambient= ambientColor;
device.Lights[ lightNo ].Range= 100.0f; 
device.Lights[ lightNo ].Enabled= true;
device.Lights[ lightNo ].Commit();
This is very simple. The device keeps track of every light and every light needs to have a unique number. The number is of type "short" which is a 16 bit variable but you can only use eight active lights at the same time (if you really need to I think there is a way to get more). Then it's just to fill in the properties of the light and call the function Commit(). There are three types of lights, directional, point and spot. The code above is for a point light. The other lights are created in the same fashion with the difference that the directional lights don't use the position attribute and the spotlight needs a direction etc. etc.

DirectXObject

This class contains the code for building a mesh from a directx mesh file (.x).

Mesh systemMemoryMesh = Mesh.FromFile( strPath, MeshFlags.SystemMemory, device, out adjacencyBuffer, out Mat ); // GraphicsStream ,ExtendedMaterial

Load the .x file. The Extended material "Mat" gets the information about texture names and material properties which (if they exist) can be found in the file. "AdjacencyBuffer" is a stream containing graphic data. This variable can be used for optimizing the mesh which is a very good thing to do.

systemMemoryMesh.OptimizeInPlace( MeshFlags.OptimizeCompact | MeshFlags.OptimizeAttrSort | MeshFlags.OptimizeVertexCache, adjacencyBuffer );

Optimize, Optimize, Optimize

for( int i = 0; i < Mat.Length; i++ )
{
materials[ i ] = Mat[ i ].Material3D;
materials[ i ].Ambient = materials[ i ].Diffuse;

if ( Mat[ i ].TextureFilename != null )
{
// Create the texture
string texturefilename = DirectXMisc.FindFile( null, Mat[ i ].TextureFilename );
textures[ i ] = TextureLoader.FromFile( device, texturefilename );
}
}
A mesh can have many different textures. This for loop takes every texture that was found in the .x file and creates the textures.
for( int i=0; i < materials.Length; i++)
{
device.Material = materials[ i ];
device.SetTexture( 0, textures[ i ] );
systemMemoryMesh.DrawSubset( i );
}
To render the object just tell the device what material and what texture to use and then call the function DrawSubset() from the mesh object.

DirectXSound

AudioVideoPlayback.Audio mp3 = new AudioVideoPlayback.Audio("mySong.mp3");
mp3.Play();

As you can see above, to play an mp3 in a directx application is a very easy thing to do, thanks to the AudioVideoPlayback classes and functions.

DirectSound.Device soundDevice = new DirectSound.Device();
// game = the main form = System.Windows.Forms.Control
m_soundDevice.SetCooperativeLevel( game, DirectSound.CooperativeLevel.Priority ); 
DirectSound.Buffer sounds = new DirectSound.SecondaryBuffer( "myWav.wav", soundDevice );
To play sounds is a little more work. First we must create a device for the sound and then set the CooperativeLevel.

sounds.Play( 0, DirectSound.BufferPlayFlags.Default );

Then just press play

Breakout3dMap

The program I wrote to create maps. I wrote it in two hours so don't expect much.

What you can learn or copy ;)

Mp3 implementation
Sound implementation
Meshes, textures and objects (Backgrounds, 3d Fonts ..)

I'm not an expert or professional programmer. I just program on my spare time so this article could contain errors and misleading information. If it does then I'm sorry and you can write to my e-mail and yell at me :). But I hope it does more good than harm. Good luck everyone!

About the Author:

Mathias Edman
JustAnotherProgrammer@hawaii.com

Download Source Code