游戏GUI界面
1、核心凼数ProcessGUI 1.ProcessGUI函数是GUI系统中的最重要的一个函数,它渲染了整个GUI系统,同样还为控件调用了回调函数。它参数包括需要处理的GUI,
明鼠标左键是否被按下的布尔值,然后是以像素为单位的鼠标指针位置,以及指向处理控件时要用到的通用回调函数的指针。一般而言对于回调函数的话,需要两个参数,一个是控件的ID,另一个就是控件的状态。所以在源文件D3DGUIClass.cpp中添加
void ProcessGUI(D3DGUIClass *gui, bool LMBDown, int mouseX, int mouseY, void(*funcPtr)(int id, int state))
2、凼数体写法方面的话,首先获取D3D对象,渲染了背景图。他是背景图,所以显示在各控件的最下方,所以需要在绘制其他控件之前绘制它,这样就可以在它之上绘制其他控件了。所以在ProcessGUI凼数中添加代码
if(!gui)return;
LPDIRECT3DDEVICE9device = gui->GetD3dDevice();
if(!device)return;
//绘制背景
GUICONTROL*Background = gui->GetBackground();
LPDIRECT3DVERTEXBUFFER9bdBuffer = gui->GetBackgroundBuffer();
//已经创建出的东西才绘制,所以用if
if(gui->IsBackgroundUsed()&& Background && bdBuffer)
{
device->SetTexture(0,Background->m_Background);
device->SetStreamSource(0,bdBuffer, 0, sizeof(GUIVERTEX));
device->SetFVF(D3DFVF_GUI);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP,0, 2);
device->SetTexture(0,NULL);
}
3、凼数接下来要做的就是循环控件列表,并按照每个控件的类型对其加以渲染。在
循环语句中有一个switch语句,它是用来检查正在处理的控件类型的。若是静态文
本控件,就获取这个文本使用的D3D字体对象,设置一下文本位置,并且调用
DrawText来显示文本。继续添加如下代码
//用来显示文本的对象
LPD3DXFONT pFont = NULL;
RECT fontPosition = {0, 0, (long)gui->GetWindowWidth(),
(long)gui->GetWindowHeight()};
//创建一个顶点缓存对象用于按钮的渲染
LPDIRECT3DVERTEXBUFFER9 pBuffer = NULL;
int status = UGP_BUTTON_UP;
//一个循环,用于各种控件的渲染
for(int i = 0; i < gui->GetTotalControlNum(); i++)
{
//获取当前控件
GUICONTROL *pControl = gui->GetGUIControl(i);
if(!pControl) continue;
//根据不同的类型做不同的操作
switch(pControl->m_type)
{
case UGP_GUI_STATICTEXT:
//这种情况下获取字体对象
pFont = gui->GetFont(pControl->m_listID);
if(!pFont) continue;
//设置文字位置
fontPosition.left = pControl->m_xPos;
fontPosition.top = pControl->m_yPos;
// 显示文字
pFont->DrawText(NULL, pControl->m_text, -1, &fontPosition,
DT_LEFT, pControl->m_color);
break;
4.处理按钮,首先得到当前按钮使用的顶点缓存指针,这就和获取静态文本控件使用
的D3D字体对象指针差不多。然后启用透明混合处理功能,这样按钮可以有透明背
景,可以为按钮增添些许效果,在设计按钮图像时就可以有更多的选择。接下来设置
一下按钮状态。有了按钮状态的话,就可以确定要绑定的纹理了,使用if语句测试鼠
标指针的位置是否落在按钮像素内,如果按钮的四个顶点的位置把鼠标指针的位置包
含在其中了,那么就可以知道鼠标在按钮的区域里面。若鼠标指针落在按钮区域中并
且鼠标左键被按下,就知道玩家正在单击按钮,就把按键状态设成
UGP_BUTTON_DOWN。如果这都不满足的话,那么玩家就只是把鼠标指针放在了
按钮之上,并没了点击按钮,就else设成UGP_BUTTON_OVER。所以继续写如下
代码:
case UGP_GUI_BUTTON:
status = UGP_BUTTON_UP;
//获取按钮所对应的顶点缓存对象
pBuffer = gui->GetVertexBuffer(pControl->m_listID);
if(!pBuffer) continue;
//设置纹理的alpha透明选项
device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
//检查鼠标是否悬停或者点击了按钮
if(mouseX > pControl->m_xPos && mouseX < pControl->m_xPos + pControl->m_width
&&
mouseY > pControl->m_yPos && mouseY < pControl->m_yPos + pControl->m_height)
{
if(LMBDown) status = UGP_BUTTON_DOWN;
else status = UGP_BUTTON_OVER;
}
5、根据不同的鼠标和按钮之间的状态来准备不同的纹理图绑定上去
if(status == UGP_BUTTON_UP) device->SetTexture(0, pControl->m_upTex);
if(status == UGP_BUTTON_OVER) device->SetTexture(0, pControl->m_overTex);
if(status == UGP_BUTTON_DOWN) device->SetTexture(0, pControl->m_downTex); 6、然后开始进行渲染,关闭alpha混合.。
//开始渲染按钮
device->SetStreamSource(0, pBuffer, 0, sizeof(GUIVERTEX));
device->SetFVF(D3DFVF_GUI);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
//关闭alpha混合.
device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
break;
7、调用回调凼数处理控件消息
if(funcPtr) funcPtr(pControl->m_id, status);
2、实现GUI系统的多页面间切换
设计和实现出了一个GUI系统的类D3DGUIClass,然后定义一个类对象,就可以实现
游戏主窗口页面的显示。如果想实现GUI系统的多页面间切换,需要定义多个D3DGUIClass类对象,来分别代表多个GUI页面。 1、在D3DGUIClass.h头文件中声明宏
// 菜单蹋页面?的?宏ê定?义?
#define GUI_MAIN_SCREEN 1 #define GUI_START_SCREEN 2 #define GUI_LOAD_SCREEN 3
#define GUI_OPTION_SCREEN 4
// 设置一些GUI中用到的控件ID
#define STATIC_TEXT_ID 1 #define BUTTON_START_ID 2 #define BUTTON_LOAD_ID 3
#define BUTTON_OPTION_ID 4
#define BUTTON_QUIT_ID 5 #define BUTTON_BACK_ID 6 #define BUTTON_LEVEL_1_ID 7
2、在main.cpp中添加一些全局变量:
//创建四个UI类对象,分别代表四个页面?
D3DGUIClass *g_MainGUI = NULL;//主窗口
D3DGUIClass *g_StartGUI = NULL; //游戏开始窗口 D3DGUIClass *g_LoadGUI = NULL; //游?戏?载?入?窗洹?口ú D3DGUIClass *g_OptionGUI = NULL; //游?戏?设Θ?置?窗洹?口ú
int g_MainGUIFontID = -1; // GUI中D字?体?对?象ó的?ID int g_StartGUIFontID = -1; // GUI中D字?体?对?象ó的?ID int g_LoadGUIFontID = -1; // GUI中D字?体?对?象ó的?ID int g_OptionGUIFontID = -1; // GUI中D字?体?对?象ó的?ID int g_currentGUI = GUI_MAIN_SCREEN; //一?个?当獭?前?的?GUI标括?识?
3、在进行渲染资源准备的Object_Init( )凼数中,添加载入GUI系统中的资源到内
存中的相关代码。
首先,创建出这些GUI系统的页面,然后给四个页面分别添加背景图,接着分别给四个页面添加字体
// 创洹?建?一?些?GUI系μ统?
g_MainGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT); //主?菜?单蹋?页?面?
g_StartGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT); //开a始?新?游?戏?页?面?
g_LoadGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT); //载?入?游?戏?页?面?
g_OptionGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT); //设Θ?置?页?面?
// 给?四?个?页?面?分?别纄添 ?加ó背?景?图?
if(!g_MainGUI->AddBackground(L"GameMedia/maingui.jpg")) return false;
if(!g_StartGUI->AddBackground(L"GameMedia/startgui.jpg")) return false;
if(!g_LoadGUI->AddBackground(L"GameMedia/loadgui.jpg")) return false;
if(!g_OptionGUI->AddBackground(L"GameMedia/optiongui.jpg")) return false;
// 分?别纄给?四?个?页?面?添 ?加ó字?体?
if(!g_MainGUI->CreateTextFont(L"微,软è?雅?黑ú", 28, &g_MainGUIFontID)) return false;
if(!g_StartGUI->CreateTextFont(L"微,软è?雅?黑ú", 38, &g_StartGUIFontID)) return false;
if(!g_LoadGUI->CreateTextFont(L"微,软è?雅?黑ú", 38, &g_LoadGUIFontID)) return false;
if(!g_OptionGUI->CreateTextFont(L"微,软è?雅?黑ú", 38, &g_OptionGUIFontID)) return false;
然后,是给主菜单页面添加一些布局的代码:
// 添 ?加ó静2态?文?本?到?页?面?中D
if(!g_MainGUI->AddStaticText(STATIC_TEXT_ID, L"张郑强",
1170, 735, D3DCOLOR_XRGB(55,155,255), g_MainGUIFontID)) return false;
if(!g_MainGUI->AddStaticText(STATIC_TEXT_ID, L"学号:1104685003",
500, 150, D3DCOLOR_XRGB(255,255,255), g_MainGUIFontID)) return false;
//添加4个按钮,分别是开始游戏,载入进度,选项和退出游戏,每个按钮对应3幅图
if(!g_MainGUI->AddButton(BUTTON_START_ID, 650, 340, L"GameMedia\\startUp.png",
L"GameMedia\\StartOver.png", L"GameMedia\\startDown.png")) return false;
if(!g_MainGUI->AddButton(BUTTON_LOAD_ID, 650, 385, L"GameMedia\\loadUp.png",
L"GameMedia\\loadOver.png", L"GameMedia\\loadDown.png")) return false;
if(!g_MainGUI->AddButton(BUTTON_OPTION_ID, 650, 430, L"GameMedia\\optionsUp.png",
L"GameMedia\\optionsOver.png", L"GameMedia\\optionsDown.png")) return false;
if(!g_MainGUI->AddButton(BUTTON_QUIT_ID, 650, 475, L"GameMedia\\quitUp.png",
L"GameMedia\\quitOver.png", L"GameMedia\\quitDown.png")) return false; 接着,是给开始新游戏页面添加一些布局的代码:
// 添加按钮到页面中
if(!g_StartGUI->AddButton(BUTTON_LEVEL_1_ID,550, 380, L"GameMedia/level1Up.png",
L"GameMedia/level1Over.png",
L"GameMedia/level1Down.png")) return false;
if(!g_StartGUI->AddButton(BUTTON_BACK_ID, 750, 350, L"GameMedia/backUp.png", L"GameMedia/backOver.png",
L"GameMedia/backDown.png")) return false;
给载入游戏页面添加一些布局的代码:
//添 ?加ó静2态?文?本?到?页?面?中D
if(!g_LoadGUI->AddStaticText(STATIC_TEXT_ID, L"这a里?是?load game页?面?",
411, 340, D3DCOLOR_XRGB(33,255,55), g_LoadGUIFontID)) return false;
// 添 ?加ó按恪?钮,到?页?面?中D
if(!g_LoadGUI->AddButton(BUTTON_BACK_ID, 750, 400, L"GameMedia/backUp.png", L"GameMedia/backOver.png",
L"GameMedia/backDown.png")) return false;
给option页面加上一些布局的代码:
// 添 ?加ó按恪?钮,到?页?面?中D
if(!g_OptionGUI->AddButton(BUTTON_BACK_ID, 750, 450, L"GameMedia/backUp.png", L"GameMedia/backOver.png",
L"GameMedia/backDown.png")) return false;
//添 ?加ó静2态?文?本?到?页?面?中D
if(!g_OptionGUI->AddStaticText(STATIC_TEXT_ID, L"这a里?是?Option页?面?",
540, 60, D3DCOLOR_XRGB(33,55,255), g_OptionGUIFontID)) return false; 修改GUI系统的回调凼数:
void GUICallback(int id, int state)
{
switch(id)
{
case BUTTON_START_ID: //start game开a始?游?戏?按恪?钮,
if(state == UGP_BUTTON_DOWN)
g_currentGUI = GUI_START_SCREEN;
break;
case BUTTON_LOAD_ID: //load game载?入?游?戏?按恪?钮,
if(state == UGP_BUTTON_DOWN)
g_currentGUI = GUI_LOAD_SCREEN;
break;
case BUTTON_OPTION_ID: //option设Θ?置?按恪?钮,
if(state == UGP_BUTTON_DOWN)
g_currentGUI = GUI_OPTION_SCREEN;
break;
case BUTTON_BACK_ID: //back返う?回?按恪?钮,
if(state == UGP_BUTTON_DOWN)
g_currentGUI = GUI_MAIN_SCREEN;
break;
case BUTTON_QUIT_ID://quit退?出?按恪?钮,
if(state == UGP_BUTTON_DOWN)
PostQuitMessage(0);
break;
case BUTTON_LEVEL_1_ID: //start game开a始?游?戏?页?面?中D,?Level1按恪?钮,
//等台?级?一?的?游?戏?从洙?这a里?开a始?写′代洙?码?
break;
}
}
用if 、else if、else组合句,处理和渲染GUI系统,表示出几个页面之前的逻辑关系。
// 描è述?:阰使?用?Direct3D进?行D渲?染?
//-------------------------------------------------------------------------------------
-------------
void Direct3D_Render(HWND hwnd,FLOAT fTimeDelta)
{
// 清?屏á操ù作痢?
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
D3DCOLOR_XRGB(100, 255, 255), 1.0f, 0);
// 开a始?绘?制?
g_pd3dDevice->BeginScene(); // 开a始?绘?制?
正y式?绘?制?
?处鋦理え?和í渲?染?GUI系μ统? // 一?个?if 、,else if、,else组哩?合?句?,
if(g_currentGUI == GUI_MAIN_SCREEN)
ProcessGUI(g_MainGUI, g_LMBDown, g_MouseX,
g_MouseY, GUICallback);
else if(g_currentGUI == GUI_START_SCREEN)
ProcessGUI(g_StartGUI, g_LMBDown, g_MouseX,
g_MouseY, GUICallback);
else if(g_currentGUI == GUI_LOAD_SCREEN)
ProcessGUI(g_LoadGUI, g_LMBDown, g_MouseX,
g_MouseY, GUICallback);
else if(g_currentGUI == GUI_OPTION_SCREEN)
ProcessGUI(g_OptionGUI, g_LMBDown, g_MouseX,
g_MouseY, GUICallback);
else
ProcessGUI(g_MainGUI, g_LMBDown, g_MouseX,
g_MouseY, GUICallback);
//-----------------------------【?绘?制?文?字?信?息,】?-----------------------------
HelpText_Render(hwnd);
结á束?绘?制?
g_pd3dDevice->EndScene(); // 结á束?绘?制?
显?示?翻?转羇
g_pd3dDevice->Present(NULL, NULL, NULL, NULL); // 翻?转显?示?
}