一个简单而强大的游戏引擎






4.45/5 (16投票s)
2007 年 7 月 23 日
4分钟阅读

93413

9179
本文讨论了一个简单而强大的游戏引擎,
这张图片是从 3ds Max 截取的。这款 F-16 有 58,133 个顶点,构成 174,399 个三角形。
引言
本文介绍了一个使用 DirectX 的简单而强大的游戏引擎——3D、输入、音乐和显示。有了这个引擎,您可以渲染复杂的三维模型,如地形、城市、人物、汽车等,还可以播放音乐,并为音乐添加三维效果,如速度、位置和方向。您可以播放电影——任何可以使用 Windows Media Player 播放的电影——还可以使用直接输入以全速和高级用法获取键盘、鼠标和操纵杆的输入。本文包含一个 3ds Max 的插件,即游戏建模第一名,它可以将 3ds Max 场景导出到 SZM 格式。SZM 模型格式是一种非常简单但功能强大的建模格式。 这里是 SZM 模型格式的文档。
使用代码
每个 3D 游戏都有一个 Init_Game()
、Game_Loop()
和 Game_Clean_Up()
函数。在 Init_Game()
中,您初始化 DirectX 并加载所需的模型、音乐和视频。在游戏循环中,您检查是否有任何来自键盘或鼠标的输入并处理该输入。您还可以计算每个对象应该在何处。完成这些之后,您将其渲染到屏幕上。在游戏清理阶段,您执行退出游戏时所需的任何清理工作。
初始化游戏
首先,创建一个窗口。然后,在进入消息循环之前,按如下方式开始初始化:
//------------------------------------------------
::ShowWindow(g_GlobalData.hWnd,SW_SHOW);
::UpdateWindow(g_GlobalData.hWnd);
//------------------------------------------------
//
//Intialize Program.
//
if(!::Init_Game())
{
DestroyWindow(g_GlobalData.hWnd);
Return false;
}
//------------------------------------------------
下面是 Init_Game()
例程,它执行以下操作:
- 初始化一些全局变量,例如缩放和视点位置,显示边界框等。
- 初始化一些 DirectX3D 的变量,例如启用 Z 缓冲区、全局环境光、3D 光照等。
- 调用
InitDirectX3D()
。 - 创建一个要显示的物体。
- 播放一些视频,仅当您现在想看视频时。
- 视频播放完成后,如果您决定播放视频。
- 您可以播放一些音乐。
- 初始化直接输入,即鼠标和键盘输入。
- 初始化一个
CD3DFont
类。 - 初始化完成!
////////////////////////////////////////////////////
//
////////////////////////////////////////////////////
BOOL Init_Game()
{
//Move Eye position back, so you can see the scene.
g_GlobalData.CameraEyeZ = -15000;
g_GlobalData.EyeX_Rotation=0;
g_GlobalData.EyeY_Rotation=0;
g_GlobalData.EyeZ_Rotation=0;
// How much to zoom (when using the mouse wheel).
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;
//---------------------------------
// Init the values that would be past to SetRenderState
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;
//---------------------------------
//Now Init DirectX 3d.
if(!g_DirectX3D.InitDirectX3D(g_GlobalData.hWnd))
return FALSE;
//---------------------------------
// g_DirectX3D.WritePC_CapabilitiesToFile("PC_Capabilities.txt");
//---------------------------------
//Create or Load an object to display for an example.
if(!::CreateAnObjectToDisplay())
return FALSE;
//---------------------------------
//g_DirectX3D.ShowFog();
//---------------------------------
//Clear Display
g_DirectX3D.Clear_Display(TRUE,TRUE,FALSE,DISPLAY_COLOR);
g_DirectX3D.Flip();
//---------------------------------
//->Show a Video.
//---------------------------------
g_DirectShow.Play(L"Movies\\Nsync - Bye Bye Bye.mpg",g_GlobalData.hWnd);
//->Turn on some Music.
//---------------------------------
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;
}
游戏循环
在消息循环中,按如下方式调用 Prog_Loop()
:
//------------------------------------------------
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
{
// make sure we go to sleep if we have nothing else to do
::WaitMessage();
}
}
//------------------------------------------------
这是 Game_Loop()
的作用:- 它检查是否是时候从键盘和鼠标获取输入了。请注意,您可以对其进行更改,使其在每次进入
Game_Loop()
时检查输入。 - 设置变换。
- 清除显示。
- 渲染一个物体。
- 绘制文本。
- 翻转后缓冲区到前缓冲区,显示新渲染的场景。
- 渲染完成,直到下一个循环。
////////////////////////////////////////////////////
//
////////////////////////////////////////////////////
BOOL Game_Loop()
{
//Get time.
g_GlobalData.dwCurrentTime = ::timeGetTime();
//--------------------------------------
//If passed a certain time check if there is any input.
if(g_GlobalData.dwCurrentTime > (g_GlobalData.dwInputSystemOldTime+10))
{
if(g_GlobalData.bProcessInput)
{
g_Keyboard.ProcessKey();
g_Mouse.ProcessMouse();
}
g_GlobalData.dwInputSystemOldTime = g_GlobalData.dwCurrentTime;
}
//--------------------------------------
//Set Transformations.
if(!g_DirectX3D.SetTransformations())
return FALSE;
//Clear Display.
g_DirectX3D.Clear_Display(TRUE,TRUE,FALSE,DISPLAY_COLOR);
//Render Object.
g_DirectX3D.RenderObject(&g_GlobalData.Object);
//--------------------------------------
//Draw Text.
g_pFont->DrawText( 380, 0, D3DCOLOR_ARGB(255,255,0,0), "My-Game!" );
//--------------------------------------
//Flip backbuffer to front buffer.
g_DirectX3D.Flip();
return TRUE;
}
结果
您将获得以下效果:
附加功能
- 雾
- 显示文本
- 光照
- 平铺纹理
- 将 PC 功能写入文件
- 窗口模式或全屏
如何编译
您必须拥有 DirectX 8 或 9 SDK。以下是如何包含 DX SDK 的 "include" 和 "lib" 目录的路径:
Visual Studio 6
工具 -> 选项 -> 目录 (选项卡) -> (包含文件) / (库文件) 从组合框中 -> 添加路径
Visual Studio 8 (VS 2005)
工具 -> 选项 -> 项目和解决方案 (从树状视图) -> Visual C++ 目录 -> (包含文件) / (库文件) -> 添加路径
最好将新添加的路径放在列表的最后。
SZM 3D 模型格式
在文件开头,有一个 SZM_File_header
结构。紧随其后的是一个 DWORD
,它保存 MyMesh
结构的数量。这就是文件头:
////////////////////////////////////////////////////
// Header
////////////////////////////////////////////////////
typedef struct _SZM_File_header
{
DWORD SZM_Sig;//'SZM '
DWORD version1;//'0004'
DWORD version2;//'0001'
}
SZM_File_header;
这是保存文件中网格数量的 DWORD
:
////////////////////////////////////////////////////
//
////////////////////////////////////////////////////
DWORD nMeshesInFile; // Number of meshes in the file.
这是 MyMesh
的声明方式:
////////////////////////////////////////////////////
// Now comes nMeshesInFile of MyMesh structures.
////////////////////////////////////////////////////
typedef struct _MyMesh
{
//--------------------------
DWORD nMeshName; // strlen(szMeshName)+1
char *szMeshName; // Mesh name.
DWORD nTextureFileName; // strlen(szTextureFileName)+1
char *szTextureFileName;// Texture File Name.
float UTilingData; // Texture n tiling at the U axis.
float VTilingData; // Texture n tiling at the V axis.
float UOffsetData; // Texture Offset at the U axis.
float VOffsetData; // Texture Offset at the V axis.
//--------------------------
D3DXMATRIX matTransformation;
//The transformation matrix that was applied to the mesh.
DWORD nVertex; // Number of Vertex of the mesh.
MyD3DVERTEX *pVertex; // Vertex Buffer.
//--------------------------
MyMaterial Material; // Mesh Material.
//--------------------------
// Is there a Bounding Box.
// The reason that some meshes don't have bounding boxes
// is that some meshes are part of a mesh that came before
// them, so that mesh bounding box also bounds on the following
// mesh (The reason that some mashed are divided to parts are
// because it can be meshes that different parts have a different
// material, so the mesh was divided to parts).
BOOL bHasBoundingBox;
Box BoundingBox; // Bounding Box.
Box3 MaxMinBox; // Mesh Max and Min points.
//--------------------------
DWORD nMesh; // Mesh-ID.
DWORD dwLevelInTree; // Level in the tree.
//--------------------------
}
MyMesh;
////////////////////////////////////////////////////
//
////////////////////////////////////////////////////
有关更多信息,请参见 _SZM_Format.h_ 和 _SZM_Loader.cpp_。
如何制作 3D 模型
排名第一的游戏建模软件是 3ds Max,但 3ds Max 不是免费的。如果您想要一款免费的 3D 建模软件,可以使用 Blender 3D。我并不太喜欢使用 Blender 3D,但也许您可以习惯它。有关更多信息,您可以阅读 这里。
资源和参考
评论、建议或修正
我很想听听关于本文的任何评论、建议或修正。这将激励我写更多文章。祝您游戏愉快!
历史
- 2007 年 7 月 23 日 - 首次发布