This picture was taken from 3ds Max. This F-16 has 58,133 vertices that make 174,399 triangles.
This article talks about a simple and powerful game engine that uses DirectX �3D, Input, Music and Show. With this engine you can render complex 3D models like terrains, cities, people, cars, etc., as well as play music and add 3D effects like velocity, position and direction to the music. You can play movies -- any movie that can be played by Windows Media Player -- and also use direct input for getting the keyboard, mouse and joystick input at full speed and in advanced usage. This article includes a plug-in for 3ds Max, i.e. Number 1 3D modeling for games, that exports 3ds Max scenes to the SZM format. The SZM model format is a very simple but powerful modeling format. Here is the documentation of the SZM model format.
Every 3D game has an Init_Game()
, Game_Loop()
and a Game_Clean_Up()
function. In Init_Game()
, you initialize DirectX and load the needed models, music and videos. In the game loop, you check if there is any input from the keyboard or mouse and you process the input. You also calculate where each object should be. After all this, you render it to the screen. In the game clean-up, you do any cleaning up that is needed when quitting the game.
First, create a window. Then, before entering the message loop, start the initializing like this:
::ShowWindow(g_GlobalData.hWnd,SW_SHOW);
::UpdateWindow(g_GlobalData.hWnd);
if(!::Init_Game())
{
DestroyWindow(g_GlobalData.hWnd);
Return false;
}
Below is the Init_Game()
routine and this is what it does:
- Initialize some global variables, for example the zoom and the eye position, displaying the bounding boxes, etc.
- Initialize some variables of DirectX3D, i.e. to enable Z buffer, Global Ambient, 3DLighting, etc.
- Call
InitDirectX3D()
.
- Create an object to be displayed.
- Play some video, only if you want to see a video now.
- After the video finishes playing, if you decided to play a video.
- You can play some music.
- Initialize direct input, i.e. mouse and keyboard input.
- Initialize a
CD3DFont
class.
- You are done initializing!
BOOL Init_Game()
{
g_GlobalData.CameraEyeZ = -15000;
g_GlobalData.EyeX_Rotation=0;
g_GlobalData.EyeY_Rotation=0;
g_GlobalData.EyeZ_Rotation=0;
g_GlobalData.m_dwMouseWheel = 10;
g_GlobalData.m_dwCameraMoveY = 10;
g_GlobalData.m_dwCameraMoveZ = 10;
g_GlobalData.bShowBoundingBoxs = TRUE;
g_GlobalData.bShowObjectBoundingBoxs = TRUE;
g_GlobalData.bShowWireFrame = FALSE;
g_GlobalData.dwInputSystemOldTime = 0;
g_GlobalData.bProcessInput = TRUE;
g_DirectX3D.m_bEnableZBuffer = TRUE;
g_DirectX3D.m_dwGlobalAmbient = D3DCOLOR_ARGB(255,0,0,0);
g_DirectX3D.m_bEnableDirect3DLighting = TRUE;
g_DirectX3D.m_bEnableBackFacing = FALSE;
if(!g_DirectX3D.InitDirectX3D(g_GlobalData.hWnd))
return FALSE;
if(!::CreateAnObjectToDisplay())
return FALSE;
g_DirectX3D.Clear_Display(TRUE,TRUE,FALSE,DISPLAY_COLOR);
g_DirectX3D.Flip();
g_DirectShow.Play(L"Movies\\Nsync - Bye Bye Bye.mpg",g_GlobalData.hWnd);
if(!g_DirectSound.Init())
return FALSE;
if(!g_DirectSound.Load(L"Music\\Britney Spears � Crazy.mp3"))
return FALSE;
if(!g_DirectSound.CreateAudioPath(FALSE))
return FALSE;
if(!g_DirectSound.SetVolume(-1600))
return FALSE;
if(!g_DirectSound.PlayAudioPath(0))
return FALSE;
g_GlobalData.bInitWasDone = TRUE;
if(!g_Keyboard.Init())return FALSE;
if(!g_Mouse.Init())return FALSE;
g_pFont = new CD3DFont( _T("Times New Roman"), 14, D3DFONT_BOLD );
g_pFont->InitDeviceObjects( g_DirectX3D.m_pD3dDevice );
g_pFont->RestoreDeviceObjects();
return TRUE;
}
In the message loop, call Prog_Loop()
like this:
while(1)
{
if( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
if( !::GetMessage( &msg, NULL, 0, 0 ) )
return msg.wParam;
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else if(g_GlobalData.bInitWasDone)
{
::Game_Loop();
}
else
{
::WaitMessage();
}
}
This is what
Game_Loop()
does:
- It checks if it is time to get input from the keyboard and mouse. Note that you can change it and make it check for input each time it enters
Game_Loop()
.
- Sets transformation.
- Clears the display.
- Renders an object.
- Draws text.
- Flips the back buffer to the front buffer to display the new rendered scene.
- Rendering is done until the next loop.
BOOL Game_Loop()
{
g_GlobalData.dwCurrentTime = ::timeGetTime();
if(g_GlobalData.dwCurrentTime > (g_GlobalData.dwInputSystemOldTime+10))
{
if(g_GlobalData.bProcessInput)
{
g_Keyboard.ProcessKey();
g_Mouse.ProcessMouse();
}
g_GlobalData.dwInputSystemOldTime = g_GlobalData.dwCurrentTime;
}
if(!g_DirectX3D.SetTransformations())
return FALSE;
g_DirectX3D.Clear_Display(TRUE,TRUE,FALSE,DISPLAY_COLOR);
g_DirectX3D.RenderObject(&g_GlobalData.Object);
g_pFont->DrawText( 380, 0, D3DCOLOR_ARGB(255,255,0,0), "My-Game!" );
g_DirectX3D.Flip();
return TRUE;
}
This is what you get:
- Fog
- Displaying text
- Lights
- Tilling textures
- Writing PC capabilities to a file
- Windowed or full screen
You must have the DirectX 8 or 9 SDK. This is how to include the paths of the "include" and "lib" directories of the DX SDK:
Visual Studio 6
Tools -> Options -> Directories (tab) -> (Include files) / (Library files) from the combo box-> add paths
Visual Studio 8 (VS 2005)
Tools -> Options -> Projects and solutions (from the tree view) -> Visual C++ directories -> (Include files) / (Library files) -> add paths
It is best to make the new added paths the last in the list.
At the beginning of the file, there is an SZM_File_header
structure. Right after it, there is a DWORD
that holds the number of MyMesh
structures. This is the header:
typedef struct _SZM_File_header
{
DWORD SZM_Sig;
DWORD version1;
DWORD version2;
}
SZM_File_header;
This is the DWORD
that holds the number of meshes in the file:
DWORD nMeshesInFile;
This is how MyMesh
is declared:
typedef struct _MyMesh
{
DWORD nMeshName;
char *szMeshName;
DWORD nTextureFileName;
char *szTextureFileName;
float UTilingData;
float VTilingData;
float UOffsetData;
float VOffsetData;
D3DXMATRIX matTransformation;
DWORD nVertex;
MyD3DVERTEX *pVertex;
MyMaterial Material;
BOOL bHasBoundingBox;
Box BoundingBox;
Box3 MaxMinBox;
DWORD nMesh;
DWORD dwLevelInTree;
}
MyMesh;
For more information, see SZM_Format.h and SZM_Loader.cpp.
The number 1 modeling program for games is 3ds Max, but 3ds Max is not free. If you want a free 3D modeling program, you can use Blender 3D. I don't really like to use Blender 3D, but maybe you can get used to it. For more information, you can read here.
- For more information on game engines, see here.
- For information on physics engines, see here.
- For information on game developing, see here.
I would like to hear any comments, suggestions or fixes regarding this article. This would give me the motivation to write more articles. Enjoy your game!
- 23 July, 2007 -- Original version posted