使用 Lua 控制 GUI
使用 Lua 控制 GUI
在本教程中我們將介紹以下操作的基本知識(shí):
- 創(chuàng)建一個(gè) GUI 環(huán)境并將它激活
- 創(chuàng)建一個(gè)對(duì)話框?qū)嵗?/li>
- 通過(guò)編輯 XML 來(lái)配置對(duì)話框
- 關(guān)聯(lián)到按鈕事件
本教程中我們會(huì)學(xué)習(xí)如何在 Vision 使用 Lua 來(lái)創(chuàng)建和顯示 GUI。 我們將學(xué)習(xí)如何定義布局以及如何加載 XML 并通過(guò)修改它們來(lái)顯示自定義菜單和對(duì)話框。 然后我們會(huì)在對(duì)話框中添加一個(gè)勾選框,由它來(lái)控制場(chǎng)景中一個(gè)光源的可見性。
本課程基于“Scripting Basics”教程。 如果你還不了解 Vision 和 vForge 中的腳本功能,請(qǐng)先學(xué)習(xí)基本腳本教程。因?yàn)樵诒窘坛虒W⒂?GUI 腳本而跳過(guò)關(guān)于 vForge 腳本功能的基本講解。
基本概念:
Vision 的 GUI 系統(tǒng)基于引擎的底層 2D 渲染功能。 GUI 的類會(huì)被編譯成 VisionEnginePlugin,因此在插件被加載的時(shí)候它們會(huì)被正確地初始化。 它支持對(duì)話框,事件以及很多不同種類的控件。 所需的資源和對(duì)話框布局都在 XML 資源文件中定義。
所有的GUI 資源,比如對(duì)話框布局、游標(biāo)、字體等等都通過(guò)專有的 GUI 管理器處理。 該管理器維護(hù)一個(gè)列表,管理所有使用 GUI 資源的 GUI 環(huán)境。 一個(gè) GUI 環(huán)境的實(shí)例定義了一個(gè)獨(dú)立于其它 GUI 環(huán)境的具體的狀態(tài)(例如,如果場(chǎng)景中有很多控制臺(tái)模型的實(shí)例,這些控制臺(tái)顯示帶有門禁密碼的用戶界面,每一個(gè)控制臺(tái)都可以處于不同的狀態(tài),鎖定/解鎖)。
創(chuàng)建你的第一個(gè)對(duì)話框:
我們會(huì)從一個(gè)已經(jīng)準(zhǔn)備好的場(chǎng)景開始。 我們將添加 GUI 資源以及 Lua 腳本。 你可以通過(guò)加載教程中的工程,然后打開 Scenes/GUI_LUA/GUI_LUA.scene 來(lái)使用該場(chǎng)景。
首先我們要添加一段初始化對(duì)話框的腳本。 為此,選擇場(chǎng)景的 Main Layer 然后來(lái)到 Properties 面板。 在面板中選擇 SceneScriptFile 屬性,然后在下拉菜單中選擇“New”。 新建一個(gè)名為“initGUI.lua”的腳本。
然后我們來(lái)拼接該腳本的內(nèi)容。 轉(zhuǎn)到 Script 面板并打開新新建的腳本。
我們需要兩個(gè)回調(diào)函數(shù):
- OnAfterSceneLoaded
- OnBeforeSceneUnloaded
OnAfterSceneLoaded 會(huì)在場(chǎng)景初始化后被調(diào)用。 在回調(diào)函數(shù)中,我們需要初始化 GUI 系統(tǒng)并加載所需的資源:
function OnAfterSceneLoaded(self)
GUI:LoadResourceFile("Dialogs/MenuSystem.xml") –-load resources
G.myDialog = GUI:ShowDialog("Dialogs/MainMenuLUA.xml") –-show GUI
GUI:SetCursorVisible(true) –-make the mouse cursor visible
end
Dialogs/MenuSystem.xml 和 Dialogs/MainMenuLUA.xml 已經(jīng)包含在了我們的樣例中。 MenuSystem.xml 定義了用于對(duì)話框的字體和游標(biāo)的貼圖。 MainMenuLUA.xml 定義了具體的對(duì)話框布局。 稍后我們會(huì)仔細(xì)分析這個(gè)文件并添加新的按鈕。
在我們運(yùn)行場(chǎng)景前還需要確保對(duì)話框在場(chǎng)景停止運(yùn)行的時(shí)候會(huì)再次隱藏。 為此,我們?cè)?OnBeforeSceneUnloaded 中添加下列代碼
function OnBeforeSceneUnloaded()
local mode = Application:GetEditorMode()
if mode == Vision.EDITOR_PLAY or mode == Vision.EDITOR_RUN then
GUI:SetCursorVisible(false)
GUI:CloseDialog( G.myDialog )
end
end
首先我們檢查當(dāng)前的編輯模式。 因?yàn)槲覀冎幌朐?vForge 中運(yùn)行場(chǎng)景之后關(guān)閉對(duì)話框。 當(dāng)我們通過(guò)導(dǎo)出再運(yùn)行場(chǎng)景時(shí)不應(yīng)該做這些,因?yàn)椋欠N情況下)對(duì)話框會(huì)在 OnBeforeSceneUnloaded 被觸發(fā)前就被清理干凈。
你最終的腳本應(yīng)該是這樣的:
現(xiàn)在我們準(zhǔn)備好啟動(dòng) Play-The-Game in vForge(在 vForge 中執(zhí)行游戲) 模式,你會(huì)看到如下對(duì)話框:
恭喜!
你已經(jīng)成功地在 Vision 中創(chuàng)建了一個(gè) GUI 對(duì)話框!
修改 XML 布局:
現(xiàn)在我們有了一個(gè)可以運(yùn)行的 GUI,再來(lái)看看布局是如何定義的。 對(duì)話框布局文件以 XML 形式存儲(chǔ)。 對(duì)話框的類名以及所有關(guān)于控件的信息都儲(chǔ)存在 XML 文件中。 一個(gè)典型的對(duì)話框資源 XML 是這樣的:
<root>
<DIALOG class="VDialog" name="MainMenu" fullscreen="FALSE" size="300,140" startPosition="ScreenCenter">
<control class="..." .../>
<control class="..." .../>
<control class="..." .../>
</DIALOG>
</root>
- 打開“Dialogs”文件夾中的 MainMenuLUA.xml。
- 如你所見,該 XML 定義了有三種控件的對(duì)話框布局:
- 一個(gè)顯示 Anarchy 徽標(biāo)的圖片控件。
- 一個(gè)黃顏色的文本標(biāo)簽顯示“Control Menu”。
- 一個(gè)標(biāo)為“Close”的按鈕。
來(lái)理解一下用到的語(yǔ)法。 有許多種類的控件:文本框、列表、檢索圖、滑塊等等。 可以在這里找到關(guān)于 XML 控件的完整參考說(shuō)明:
- 我們?yōu)椤癈lose”按鈕添加一個(gè)背景圖。 把下列 XML 代碼添加到 VPushButton 控件上:
<control class="VPushButton" ID="QUIT" ... >
...
<image texture="Button.tga" valign="CENTER" halign="CENTER">
<statemodifier state="mouseOver" texture="ButtonMouseOver.tga" cursor="HighMouse"/>
<statemodifier state="selected" texture="ButtonClicked.tga" cursor="HighMouse"/>
<statemodifier state="disabled" texture="ButtonDisabled.tga"/>
</image>
</control>
按鈕擁有不同的狀態(tài)(mouseOver、selected、disabled)。 你可以為每種狀態(tài)設(shè)置不同的圖片。 你還能改變與按鈕互動(dòng)時(shí)的游標(biāo)圖片。
- 保存文件并重啟 Play-The-Game 模式。 “Quit”按鈕現(xiàn)在看起來(lái)像這樣:
如果你將鼠標(biāo)移到按鈕上,你會(huì)看到按鈕和鼠標(biāo)的外觀都發(fā)生了改變。 在你點(diǎn)擊它的時(shí)候同樣會(huì)變化。
- 現(xiàn)在你可以嘗試在 XML 改變或添加控件。
恭喜!
你已經(jīng)成功地在 Vision 中修改了 GUI 布局!
為關(guān)閉按鈕添加功能
現(xiàn)在我們想為新按鈕添加一些功能。 如果用戶點(diǎn)擊了它,我們希望關(guān)閉對(duì)話框。
首先我們創(chuàng)建一個(gè)新的腳本文件來(lái)控制對(duì)話框。 來(lái)到 vForge 中的 Script 面板并在“Dialogs”文件夾中創(chuàng)建一個(gè)新的腳本,命名為“MainMenu.lua”。 添加下列代碼:
function OnItemClicked(self, item, buttons, x, y)
if (item:GetID() == GUI:GetID("QUIT")) then
self:SetVisible(false)
GUI:SetCursorVisible(false)
end
end
這個(gè)回調(diào)函數(shù)會(huì)在你每次點(diǎn)擊對(duì)話框中的按鈕時(shí)被調(diào)用。 Item::GetID 會(huì)返回按鈕在 MainMenuLUA.xml 中定義的參數(shù) ID。 所以當(dāng)我們的按鈕被點(diǎn)擊時(shí),我們將對(duì)話框隱藏。這里上下文中的“self”即代表對(duì)話框。 我們也同時(shí)隱藏游標(biāo)。
最后我們需要將對(duì)話框 xml 和新建的腳本關(guān)聯(lián)。 為此,請(qǐng)
- 打開“Dialogs”文件夾中的 MainMenuLUA.xml。
- 在對(duì)話框標(biāo)記里加入如下 xml 代碼
<DIALOG class="VDialog" name="MainMenu" fullscreen="FALSE" size="300,140" startPosition="ScreenCenter">
<script filename="MainMenu.lua" />
如果你現(xiàn)在運(yùn)行 Play-The-Game 模式,你能夠通過(guò)點(diǎn)擊“Clost”按鈕關(guān)閉對(duì)話框。
通過(guò) GUI 控制場(chǎng)景元素
最后這章我們會(huì)演示如何通過(guò)勾選框來(lái)控制一個(gè)場(chǎng)景元素。 我們希望在清除選擇框的時(shí)候關(guān)閉一個(gè)光源。 所以首先在 MainMenuLUA.xml 中添加一個(gè)勾選框:
<root>
<DIALOG class="VDialog" name="MainMenu" fullscreen="FALSE" size="300,140" startPosition="ScreenCenter">
<script filename="MainMenu.lua" />
<control class="..." .../>
…
<control class="VCheckBox" pos="30,350" size="150,25" ID="CHECKBOX1" checked="true">
<image texture="checkbox.tga">
<statemodifier state="selected" texture="checkboxMarked.tga"/>
</image>
<text text="Light enabled" font="MenuFont" color="255,255,255,255" valign="CENTER" ofs="30,0"/>
</control>
…
</DIALOG>
</root>
在你運(yùn)行 Play-The-Game 模式后會(huì)看到這樣的對(duì)話框:
然后我們?cè)趫?chǎng)景中添加一個(gè)動(dòng)態(tài)光源用來(lái)開關(guān)。
來(lái)到 Shapes Creator 面板,將 “Lights (Dynamic - Omni Light)”圖形拖拽到場(chǎng)景中。
將光源移到一個(gè)你可以看到的地方。 然后到新光源的屬性處修改顏色,比如綠色。之后在 ObjectKey 屬性處輸入字符串“switchlight”。 我們稍后會(huì)在 Lua 腳本中使用 ObjectKey 來(lái)獲得光源。
最后,讓我們?cè)?vForge 腳本面板中擴(kuò)展“MainMenu.lua”腳本。
function OnItemClicked(self, item, buttons, x, y)
if (item:GetID() == GUI:GetID("QUIT")) then
self:SetVisible(false)
GUI:SetCursorVisible(false)
elseif (item:GetID() == GUI:GetID("CHECKBOX1")) then
local switchlight = Game:GetLight("switchlight")
if switchlight:IsVisible() then
switchlight:SetVisible(false)
else
switchlight:SetVisible(true)
end
end
end
如你所見,現(xiàn)在我們檢查 ID 為“CHECKBOX1”的勾選框按鈕是否被按下。 如果是,那么我們通過(guò)函數(shù) Game:GetLight("switchlight") 獲得光源存放在一個(gè)本地變量上。 “switchlight”是先前我們賦給動(dòng)態(tài)光的 ObjectKey。 如果我們的光源可見,那么將其隱藏。 如果隱藏了,那么將其設(shè)為可見。
現(xiàn)在開始 Play-The-Game 模式。 你可以通過(guò)對(duì)話框中的勾選框來(lái)開關(guān)光源。
總結(jié):
你已經(jīng)成功完成了通過(guò) Lua 控制 GUI 的教程。 但是請(qǐng)牢記,如果你需要諸如添加動(dòng)態(tài)文字等高級(jí) GUI 功能的話,應(yīng)該使用 C++ 來(lái)創(chuàng)建 UI。 如果你對(duì)此感興趣,請(qǐng)閱讀 C++ GUI 課程。