doom3的UI系統是純數據驅動的,例如
windowDef TextTitle2
{
rect 20,341,600,55
visible 1
text "#str_00073"
forecolor 0.6,1,1,0
textscale 0.8
font "fonts/micro"
textalign 1
notime 1
onTime 0 {
transition "forecolor" "1 1 1 0" "1 1 0.8 1" "500" ;
}
onTime 1000 {
transition "forecolor" "1 1 0.8 1" "1 1 1 0" "500" ;
}
onTime 2000 {
resetTime "0" ;
}
}
這段文本定義了一個簡單的窗口。windowDef說明這是一個普通窗口,後面跟着這個窗口的名字。其他的窗口類型定義還有editDef,choiceDef,sliderDef,listDef,fieldDef等等,都是在普通窗口的
基礎上增加了一些行爲和屬性,本文不打算詳述。
後面緊接着是一些窗口屬性值,這些屬性可以分爲兩類,InternalVar和WinVar。
InternalVar是一些常量,定義後就不能改變,例如textalignx,texaligny,bordersize,font等
而WinVar屬性,是在運行時可以被改變的屬性,例如
visible,
backColor,
matColor,
foreColor,
hoverColor,
borderColor,
textScale,
rotate,
text
等。這些值可以在後面要提到的GUI腳本中被改變。
onTime是一個event,event會在某種條件下被調用。例如onTime event是在時間到達後面的值(毫秒)時被調用。
調用執行的內容是中括號中描述的GUI腳本。
event的類型有
onTime,
onMouseEnter ,
onMouseExit ,
onAction ,
onActivate ,
onDeactivate ,
onESC ,
onEvent ,
onTrigger ,
onActionRelease ,
onEnter ,
onEnterRelease
transition是一個GUI腳本命令,它描述了一個WinVar跟據時間被平滑的插值的過程
transition "forecolor" "1 1 1 0" "1 1 0.8 1" "500" ;
表示前景色forecolor在500毫秒內從 "1 1 1 0"過渡到"1 1 0.8 1"到這裏你應該已經能夠看出來,這段文本數據描述了一個以兩秒爲週期不斷變換顏色的文字lable。
好,我們再來看一個複雜一點的例子
windowDef Desktop
{
rect 0 ,0 ,640 ,480
backcolor 0, 0, 0, 0.9
windowDef CircleClamp
{
rect 7, 7, 626, 466
visible 1
windowDef Circle0
{
rect -95,-174,820,820
visible 1
background "gui/spin1"
matcolor 0.5, 0, 0, 0.5
}
}
windowDef TextButton2
{
rect 0,0,0,0
text "#str_00010"
textscale 1.2
forecolor 1,1,1,0
visible 1
textalign 1
font "fonts/micro"
noevents 1
onMouseEnter {
transition "forecolor" "1 1 1 0.6" "1 1 1 1" "300" ;
transition "btn2_top::matcolor" "1 1 1 1" "0.8 1 1 0.7" "300" ;
transition "btn2_corner1::matcolor" "1 1 1 1" "0.4 1 1 0.7" "300" ;
transition "btn2_corner2::matcolor" "1 1 1 1" "0.4 1 1 0.7" "300" ;
transition "btn2_bottom::matcolor" "1 1 1 1" "0.4 1 1 0.7" "300" ;
transition "btn2_corner3::matcolor" "1 1 1 1" "0.4 1 1 0.7" "300" ;
transition "btn2_corner4::matcolor" "1 1 1 1" "0.4 1 1 0.7" "300" ;
transition "btn2_right::matcolor" "1 1 1 1" "0.4 1 1 0.7" "300" ;
transition "btn2_left::matcolor" "1 1 1 1" "0.4 1 1 0.7" "300" ;
transition "btn2_fill::backcolor" "1 1 1 0.465" "0.4 1 1 0.32" "300" ;
}
onMouseExit {
transition "forecolor" "1 1 1 1" "1 1 1 0.6" "200" ;
transition "btn2_top::matcolor" "0.8 1 1 0.7" "1 1 1 0.5" "300" ;
transition "btn2_corner1::matcolor" "0.4 1 1 0.7" "0.4 1 1 0.5" "300" ;
transition "btn2_corner2::matcolor" "0.4 1 1 0.7" "0.4 1 1 0.5" "300" ;
transition "btn2_bottom::matcolor" "0.4 1 1 0.7" "0.4 1 1 0.5" "300" ;
transition "btn2_corner3::matcolor" "0.4 1 1 0.7" "0.4 1 1 0.5" "300" ;
transition "btn2_corner4::matcolor" "0.4 1 1 0.7" "0.4 1 1 0.5" "300" ;
transition "btn2_right::matcolor" "0.4 1 1 0.7" "0.4 1 1 0.5" "300" ;
transition "btn2_left::matcolor" "0.4 1 1 0.7" "0.4 1 1 0.5" "300" ;
transition "btn2_fill::backcolor" "0.4 1 1 0.32" "0.4 1 1 0.232" "300" ;
}
onAction {
if ("gui::gui_parm4" == 1) {
set "cmd" "play guisounds_error" ;
resetTime "AccessDenied" "0" ;
set "noevents" "1" ;
} else {
set "cmd" "activate ; play guisounds_click" ;
resetTime "AccessLocked" "0" ;
set "noevents" "1" ;
}
}
}
windowDef Static
{
rect -10 ,-10 ,-660 ,500
visible 1
background "gui/static"
matcolor 1, 1, 1, pdhalffade[ time * 0.001 ] / 8
}
}
首先,ui的定義是嵌套的,實際上,遊戲中的用到的ui都是比較複雜的層次結構。任意多層的各種組件嵌套組合起來,理論上可以形成任意複雜的UI效果。
然後我們看到了更多的event的使用,onMouseEnter,和onMouseExit實現了鼠標移入移出時的變化效果。
在onAction event中我們看到GUIScript中是可以帶邏輯的,不過GUIScript中也只有“if”這一種邏輯。
GUI腳本中的命令有
set,
setFocus,
endGame,
resetTime,
showCursor,
resetCinematics,
transition,
localSound,
runScript,
evalRegs,
set命令可以直接設置某個WinVar。比如
set "Circle7::visible" "0" ;
將窗口Circle7的WinVar visible的值設爲0,即隱藏這個窗口。
但如果set的參數是cmd,則其功能是讓觸發這個GUI event的對象執行後面的GUI command,可謂“腳本套腳本”,例如
一個player對象(某個玩家或NPC),觸發了這個onEvent,event中調用了
set "cmd" "activate ; play guisounds_click" ;
則這個player對象執行GUI command
activate
play guisounds_click
效果是,這個player作爲activator激活了這個GUI所在的entity,並播放音效guisounds_click
常用的GUI command有
activate
runScript
play
setkeyval
setshaderparm等
最後.....
matcolor 1, 1, 1, pdhalffade[ time * 0.001 ] / 8
WinVar的值可以是一個表達式並且還能查表有木有總結
doom3引擎的UI系統通過WinVar,GUI event,GUI Script,GUI Command等幾個核心抽象,用最少的代碼,
實現了極其靈活而強大的功能。