Nebula2探秘14-nGuiServer的创建与使用
happykevins文
关于nGui:
nGui是Nebula2本身集成的GUI系统。虽然Radon在mangalore中已经集成了对CEGUI的支持,但是nGui相比之下更加简单易用,而且紧密地与Nebula2结合,不存在CEGUI诸多的兼容性问题。另外其天生支持中文,所以在制作简单的游戏UI时可以考虑使用nGui系统。CEGUI是一个非常流行的开源的GUI系统,目前版本是0.5,虽然Bug很多而且不支持中文(网上已有很多的解决方案),但是其功能强大,并且CEGUI社区正在积极制作其相关工具,想要制作精美且复杂的UI系统的话可以考虑使用。在之后的教程中我会介绍在Nebula2中集成CEGUI的方法。
nGui的维护:
像一般的NebulaServers一样,nGui的创建过程大概分为3步:1.向Kernel添加ngui包;2.在kernel中创建nguiserver;3.调用nguiserver的初始化方法(Open)。另外在游戏循环中每帧都需要调用Trigger的方法以保证ngui正确处理用户输入,这需要有ninputserver的支持。最后在程序结束前要调用Close()方法以确保ngui正确释放资源。
nGui的初始化:
nGui的过程分为3步:1.设置nGui的skin。2.定制画刷列表。3.添加用户控件。其中前两个步骤Nebula2在startup.tcl中已经提供了默认的实现,用户也可以自由替换这些信息以实现自己期待的效果。添加用户控件可以通过两个途径来实现:1.通过kernelserver的new来创建。2.通过guiserver的newwindow来创建。其实他们本质上没有什么区别,guiserver也是通过kernelserver来创建的,只不过帮你维护了当前rootwindow的noh路径而已,nGui的所有控件都存放在noh的"/res/gui"下。
nGui的事件注册:
nGui的事件可以通过每个控件的SetXXCammond(cmd_name)来注册(XX为事件类型),传入参数cmd_name为脚本中对应的事件处理函数名,使用起来非常方便。
程序代码如下:
/*
**************************************************************************
*/
/*
Nebula2-Tutorial14
*/
/*
UsingnGuiServer
*/
/*
author:happykevins
*/
/*
**************************************************************************
*/
///
----------------------------------------------------------------------------
///
+必要头文件
//
nebula2includes
#include
"
kernel/nkernelserver.h
"
#include
"
kernel/nfileserver2.h
"
#include
"
script/ntclserver.h
"
#include
"
gfx2/nd3d9server.h
"
#include
"
gfx2/ncamera2.h
"
#include
"
gui/nguiserver.h
"
#include
"
tools/nmayacamcontrol.h
"
#include
"
scene/nsceneserver.h
"
#include
"
gui/nguiwindow.h
"
#include
"
gui/nguilabel.h
"
#include
"
gui/nguitextlabel.h
"
#include
"
gui/nguitextbutton.h
"
#include
"
../NebulaUtils/nutildefs.h
"
#include
"
../NebulaUtils/nkernelinfo.h
"
///
-必要头文件
///
----------------------------------------------------------------------------
///
----------------------------------------------------------------------------
///
+链接库
#pragma
comment(lib,"wsock32.lib")
#pragma
comment(lib,"d_microtcl.lib")
#pragma
comment(lib,"d_nkernel.lib")
#pragma
comment(lib,"d_nnebula.lib")
#pragma
comment(lib,"d_ntoollib.lib")
#pragma
comment(lib,"d_ngui.lib")
#pragma
comment(lib,"dxguid.lib")
#pragma
comment(lib,"dxerr9.lib")
#pragma
comment(lib,"d3d9.lib")
#pragma
comment(lib,"d3dx9d.lib")
#pragma
comment(lib,"dinput8.lib")
#pragma
comment(lib,"d_ndinput8.lib")
#pragma
comment(lib,"d_ndirect3d9.lib")
///
-链接库
///
----------------------------------------------------------------------------
///
----------------------------------------------------------------------------
///
+声明使用的Nebula2Package&Module
nNebulaUseModule(ntclserver);
nNebulaUseModule(nresource);
nNebulaUseModule(nresourceserver);
nNebulaUseModule(ninputserver);
nNebulaUseModule(nfont2);
nNebulaUseModule(nmesh2);
nNebulaUseModule(nmesharray);
nNebulaUseModule(nshader2);
nNebulaUseModule(ntexture2);
nNebulaUseModule(ngfxserver2);
nNebulaUseModule(nsceneserver);
nNebulaUseModule(nshadowserver2);
nNebulaUseModule(nscenenode);
nNebulaUseModule(ntransformnode);
nNebulaUseModule(nabstractcameranode);
nNebulaUseModule(nclippingcameranode);
nNebulaUseModule(nreflectioncameranode);
nNebulaUseModule(nvariableserver);
nNebulaUseModule(nconserver);
nNebulaUsePackage(ngui);
nNebulaUsePackage(ndirect3d9);
nNebulaUsePackage(ndinput8);
///
-声明使用的Nebula2Package&Module
///
----------------------------------------------------------------------------
nCamera2cam;
nMayaCamControlccam;
nKernelInfoHelperks_info(NULL);
nTclServer
*
tcl
=
NULL;
nKernelServer
*
ks
=
NULL;
nD3D9Server
*
gfx2
=
NULL;
nInputServer
*
input
=
NULL;
nSceneServer
*
scene
=
NULL;
nGuiServer
*
gui
=
NULL;
///
----------------------------------------------------------------------------
///
+添加GUI控件
///
void
SetupGUI()
{
const
float
borderSize
=
0.02f
;
//
createadummyrootwindow
//
gui->SetRootWindowPointer(0);
nGuiWindow
*
userRootWindow
=
gui
->
NewWindow(
"
nguiwindow
"
,
true
);
n_assert(userRootWindow);
rectanglenullRect(vector2(
0.0f
,
0.0f
),vector2(
1.0f
,
1.0f
));
userRootWindow
->
SetRect(nullRect);
//
nGuiWindow*userRootWindow=gui->GetRootWindowPointer();
ks
->
PushCwd(userRootWindow);
//
createlogolabel
nGuiLabel
*
rightLabel
=
(nGuiLabel
*
)ks
->
New(
"
nguilabel
"
,
"
RightLogo
"
);
n_assert(rightLabel);
vector2rightLabelSize
=
gui
->
ComputeScreenSpaceBrushSize(
"
n2logo
"
);
rectanglerightRect;
rightRect.v0.
set
(
1.0f
-
rightLabelSize.x
-
borderSize,
1.0f
-
rightLabelSize.y
-
borderSize);
rightRect.v1.
set
(
1.0f
-
borderSize,
1.0f
-
borderSize);
rightLabel
->
SetRect(rightRect);
rightLabel
->
SetDefaultBrush(
"
n2logo
"
);
rightLabel
->
SetPressedBrush(
"
n2logo
"
);
rightLabel
->
SetHighlightBrush(
"
n2logo
"
);
rightLabel
->
OnShow();
//
createahelptextlabel
nGuiTextLabel
*
textLabel
=
(nGuiTextLabel
*
)ks
->
New(
"
nguitextlabel
"
,
"
HelpLabel
"
);
n_assert(textLabel);
textLabel
->
SetText(
"
Esc:系统菜单请不要点击"Har/Scn/Dis/Cha" 由于没有连接以上服务,会导致程序崩溃!
"
);
textLabel
->
SetFont(
"
GuiSmall
"
);
textLabel
->
SetAlignment(nGuiTextLabel::Left);
textLabel
->
SetColor(vector4(
1.0f
,
1.0f
,
1.0f
,
1.0f
));
textLabel
->
SetClipping(
false
);
vector2textExtent
=
textLabel
->
GetTextExtent();
rectangletextRect(vector2(
0.0f
,
0.0f
),textExtent);
textLabel
->
SetRect(textRect);
textLabel
->
OnShow();
//
createacustombutton
nGuiTextButton
*
toggleBtn
=
(nGuiTextButton
*
)ks
->
New(
"
nguitextbutton
"
,
"
ToggleBtn
"
);
n_assert(toggleBtn);
toggleBtn
->
SetText(
"
系统菜单
"
);
toggleBtn
->
SetCommand(
"
UIEvent_ToggleBtn
"
);
//
脚本中的函数名
toggleBtn
->
SetFont(
"
GuiSmall
"
);
toggleBtn
->
SetAlignment(nGuiTextButton::Center);
toggleBtn
->
SetRect(rectangle(vector2(
0.0f
+
borderSize,
1
-
0.1f
+
borderSize),vector2(
0.15f
-
borderSize,
1.0f
-
borderSize)));
toggleBtn
->
SetDefaultBrush(
"
button_n
"
);
toggleBtn
->
SetPressedBrush(
"
button_p
"
);
toggleBtn
->
SetHighlightBrush(
"
button_h
"
);
toggleBtn
->
OnShow();
ks
->
PopCwd();
//
setthenewuserrootwindow
gui
->
SetRootWindowPointer(userRootWindow);
}
///
///
+添加GUI控件
///
----------------------------------------------------------------------------
///
----------------------------------------------------------------------------
///
+初始化环境,创建需要的Server
///
bool
InitApp()
{
///
创建KernelServer
ks
=
n_new(nKernelServer);
///
----------------------------------------------------------------------------
///
+向KernelServer中添加Package&Module
nNebulaAddModule(ntclserver);
nNebulaAddModule(nresource);
nNebulaAddModule(nresourceserver);
nNebulaAddModule(ninputserver);
nNebulaAddModule(nfont2);
nNebulaAddModule(nmesh2);
nNebulaAddModule(nmesharray);
nNebulaAddModule(nshader2);
nNebulaAddModule(ntexture2);
nNebulaAddModule(ngfxserver2);
nNebulaAddModule(nsceneserver);
nNebulaAddModule(nshadowserver2);
nNebulaAddModule(nscenenode);
nNebulaAddModule(ntransformnode);
nNebulaAddModule(nabstractcameranode);
nNebulaAddModule(nclippingcameranode);
nNebulaAddModule(nreflectioncameranode);
nNebulaAddModule(nvariableserver);
nNebulaAddModule(nconserver);
ks
->
AddPackage(ndinput8);
ks
->
AddPackage(ngui);
ks
->
AddPackage(ndirect3d9);
///
+向KernelServer中添加Package&Module
///
----------------------------------------------------------------------------
///
获得FileServer设置shaders的路径
nFileServer2
*
file
=
(nFileServer2
*
)ks
->
Lookup(
"
sys/servers/file2
"
);
///
设置系统路径
file
->
SetAssign(
"
home
"
,
"
bin:../../
"
);
file
->
SetAssign(
"
renderpath
"
,
"
home:datafiles/shaders
"
);
file
->
SetAssign(
"
shaders
"
,
"
renderpath:fixed
"
);
file
->
SetAssign(
"
scripts
"
,
"
home:datafiles/scripts
"
);
///
创建tclserver
tcl
=
(nTclServer
*
)ks
->
New(
"
ntclserver
"
,
"
/sys/servers/script
"
);
///
创建ResourceServer
ks
->
New(
"
nresourceserver
"
,
"
/sys/servers/resource
"
);
///
创建variableserver
ks
->
New(
"
nvariableserver
"
,
"
/sys/servers/variable
"
);
///
创建guiserver(RenderPath依赖)
gui
=
(nGuiServer
*
)ks
->
New(
"
nguiserver
"
,
"
/sys/servers/gui
"
);
///
创建ConsoleServer(RenderPath依赖)
ks
->
New(
"
nconserver
"
,
"
/sys/servers/console
"
);
///
创建InputServer(GuiServer依赖)
input
=
(nInputServer
*
)ks
->
New(
"
ndi8server
"
,
"
/sys/servers/input
"
);
///
创建D3D9Server
gfx2
=
(nD3D9Server
*
)ks
->
New(
"
nd3d9server
"
,
"
/sys/servers/gfx
"
);
///
创建sceneserver
scene
=
(nSceneServer
*
)ks
->
New(
"
nsceneserver
"
,
"
/sys/servers/scene
"
);
///
创建shadowserver
ks
->
New(
"
nshadowserver2
"
,
"
/sys/servers/shadow
"
);
///
初始化显示模式
nDisplayMode2mode;
mode.SetXPos(
150
);
mode.SetYPos(
100
);
mode.SetWidth(
640
);
mode.SetHeight(
480
);
///
将显示模式应用到d3d9server
gfx2
->
SetDisplayMode(mode);
gfx2
->
SetCamera(cam);
///
启动sceneserver(启动d3d9server)
scene
->
SetRenderPathFilename(
"
renderpath:dx7_renderpath.xml
"
);
if
(
!
scene
->
Open())
{
return
false
;
}
///
启动GUIServer
nStringret;
tcl
->
RunScript(
"
scripts:T14_GuiServer.tcl
"
,ret);
gui
->
Open();
///
启动InputServer
input
->
Open();
ret.Clear();
tcl
->
RunFunction(
"
OnT14MapInput
"
,ret);
///
设置GUI环境
SetupGUI();
return
true
;
}
///
///
+初始化环境,创建需要的Server
///
----------------------------------------------------------------------------
///
----------------------------------------------------------------------------
///
+初始化环境,创建需要的Server
///
bool
CloseApp()
{
///
关闭GUIServer
gui
->
Close();
///
关闭sceneserver(关闭d3d9server)
scene
->
Close();
///
销毁KernelServer
n_delete(ks);
return
true
;
}
///
///
+初始化环境,创建需要的Server
///
----------------------------------------------------------------------------
///
----------------------------------------------------------------------------
///
+Application
int
main(
int
argc,
const
char
**
argv)
{
///
初始化Application
if
(
!
InitApp())
{
n_error(
"
程序初始化失败!
"
);
return
0
;
}
ks_info.SetKernelServer(ks);
ks_info.LogNOH(
"
/
"
);
///
这里相当于游戏循环,gfx2->Trigger()将触发win32的消息泵
while
(gfx2
->
Trigger()
&&
tcl
->
Trigger())
{
///
TriggerTimeServer
nTimeServer::Instance()
->
Trigger();
double
time
=
nTimeServer::Instance()
->
GetTime();
///
TriggerInputServer
input
->
Trigger(time);
///
处理GUI事件,需要inputserver的支持
gui
->
Trigger();
///
BeginScene(BeginFrame)
if
(scene
->
BeginScene(ccam.GetViewMatrix()))
{
//
RenderScene
scene
->
RenderScene();
//
EndScene
scene
->
EndScene();
//
PresentScene(EndFrame)
scene
->
PresentScene();
}
///
FlushEvents
input
->
FlushEvents();
n_sleep(
0.00f
);
}
///
释放资源
if
(
!
CloseApp())
{
n_error(
"
释放资源失败!
"
);
return
0
;
}
return
0
;
}
///
-Application
///
----------------------------------------------------------------------------
脚本代码如下:
#
-------------------------------------------------------------------------------
#T14_GuiServer.tcl
#
#ThisisextractfromthethecentralNebularuntimestartupscript
#whichisusedforNebula2TutorialGuiServer
#
#ThescriptmainlysetsupthenGuiVariablesandMapInputs
#
#(C)2003RadonLabsGmbH
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
#OnGuiServerOpen
#
#ThisfunctioniscalledwhentheNebula2GUIserverisopened.
#-------------------------------------------------------------------------------
procOnGuiServerOpen{}{
setcwd[psel]
#
工具提示
#initializethedefaulttooltip
setguiRoot[
/
sys
/
servers
/
gui
.
getrootpath]
sel
$guiRoot
newnguitooltipTooltip
selTooltip
.
setdefaultbrush
"
tooltip
"
.
setfont
"
GuiSmall
"
.
setcolor
0
0
0
1
.
setalignment
"
left
"
.
setborder
0.005
0.005
sel
..
#
设置Gui外观相关信息
#definethesystemskin
setskin[
/
sys
/
servers
/
gui
.
newskin
system
]
sel
$skin
#
settexturepathpre-andpostfix(NOTE:don'tchangepathtotextures:system!!!)
.
settextureprefix
"
home:datafiles/textures/system/
"
.
settexturepostfix
"
.dds
"
#
activeandinactivewindowmodulationcolor
.
setactivewindowcolor
1.0
1.0
1.0
1.0
.
setinactivewindowcolor
0.6
0.6
0.6
0.6
.
setbuttontextcolor
0.0
0.0
0.0
1.0
.
settitletextcolor
0.0
0.0
0.0
1.0
.
setlabeltextcolor
0.0
0.0
0.0
1.0
.
setentrytextcolor
0.0
0.0
0.0
1.0
.
settextcolor
0.0
0.0
0.0
1.0
.
setmenutextcolor
0.0
0.0
0.0
1.0
#
####################################################################
#+添加画刷
#
#definebrushes
.
beginbrushes
#
windowtitlebar,windowbackground,tooltipbackground
.
addbrushtitlebarskin
66
152
10
20
1.0
1.0
1.0
1.0
.
addbrushwindowskin
8
154
4
4
1.0
1.0
1.0
1.0
.
addbrushtooltipskin
8
154
4
4
1.0
1.0
0.878
0.8
.
addbrushpinkskin
8
154
4
4
1.0
0.0
1.0
1.0
.
addbrushdragboxskin
8
154
4
4
1.0
0.8
0.8
0.5
#
textentryfield
.
addbrushtextentry_nskin
446
124
8
8
0.7
0.7
0.7
1.0
.
addbrushtextentry_pskin
446
124
8
8
0.8
0.8
0.8
1.0
.
addbrushtextentry_hskin
446
124
8
8
0.9
0.9
0.9
1.0
.
addbrushtextcursorskin
446
124
8
8
0.4
0.4
0.4
1.0
#
thewindowclosebutton
.
addbrushclose_nskin
388
40
16
16
1.0
1.0
1.0
1.0
.
addbrushclose_hskin
404
40
16
16
1.0
1.0
1.0
1.0
.
addbrushclose_pskin
420
40
16
16
1.0
1.0
1.0
1.0
#
thewindowsizebutton