使用 Lua 控制 GUI
使用 Lua 控制 GUI
在本教程中我们将介绍以下操作的基本知识:
- 创建一个 GUI 环境并将它激活
- 创建一个对话框实例
- 通过编辑 XML 来配置对话框
- 关联到按钮事件
本教程中我们会学习如何在 Vision 使用 Lua 来创建和显示 GUI。 我们将学习如何定义布局以及如何加载 XML 并通过修改它们来显示自定义菜单和对话框。 然后我们会在对话框中添加一个勾选框,由它来控制场景中一个光源的可见性。
本课程基于“Scripting Basics”教程。 如果你还不了解 Vision 和 vForge 中的脚本功能,请先学习基本脚本教程。因为在本教程将专注于 GUI 脚本而跳过关于 vForge 脚本功能的基本讲解。
基本概念:
Vision 的 GUI 系统基于引擎的底层 2D 渲染功能。 GUI 的类会被编译成 VisionEnginePlugin,因此在插件被加载的时候它们会被正确地初始化。 它支持对话框,事件以及很多不同种类的控件。 所需的资源和对话框布局都在 XML 资源文件中定义。
所有的GUI 资源,比如对话框布局、游标、字体等等都通过专有的 GUI 管理器处理。 该管理器维护一个列表,管理所有使用 GUI 资源的 GUI 环境。 一个 GUI 环境的实例定义了一个独立于其它 GUI 环境的具体的状态(例如,如果场景中有很多控制台模型的实例,这些控制台显示带有门禁密码的用户界面,每一个控制台都可以处于不同的状态,锁定/解锁)。
创建你的第一个对话框:
我们会从一个已经准备好的场景开始。 我们将添加 GUI 资源以及 Lua 脚本。 你可以通过加载教程中的工程,然后打开 Scenes/GUI_LUA/GUI_LUA.scene 来使用该场景。
首先我们要添加一段初始化对话框的脚本。 为此,选择场景的 Main Layer 然后来到 Properties 面板。 在面板中选择 SceneScriptFile 属性,然后在下拉菜单中选择“New”。 新建一个名为“initGUI.lua”的脚本。
然后我们来拼接该脚本的内容。 转到 Script 面板并打开新新建的脚本。
我们需要两个回调函数:
- OnAfterSceneLoaded
- OnBeforeSceneUnloaded
OnAfterSceneLoaded 会在场景初始化后被调用。 在回调函数中,我们需要初始化 GUI 系统并加载所需的资源:
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 已经包含在了我们的样例中。 MenuSystem.xml 定义了用于对话框的字体和游标的贴图。 MainMenuLUA.xml 定义了具体的对话框布局。 稍后我们会仔细分析这个文件并添加新的按钮。
在我们运行场景前还需要确保对话框在场景停止运行的时候会再次隐藏。 为此,我们在 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
首先我们检查当前的编辑模式。 因为我们只想在 vForge 中运行场景之后关闭对话框。 当我们通过导出再运行场景时不应该做这些,因为(那种情况下)对话框会在 OnBeforeSceneUnloaded 被触发前就被清理干净。
你最终的脚本应该是这样的:
现在我们准备好启动 Play-The-Game in vForge(在 vForge 中执行游戏) 模式,你会看到如下对话框:
恭喜!
你已经成功地在 Vision 中创建了一个 GUI 对话框!
修改 XML 布局:
现在我们有了一个可以运行的 GUI,再来看看布局是如何定义的。 对话框布局文件以 XML 形式存储。 对话框的类名以及所有关于控件的信息都储存在 XML 文件中。 一个典型的对话框资源 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 定义了有三种控件的对话框布局:
- 一个显示 Anarchy 徽标的图片控件。
- 一个黄颜色的文本标签显示“Control Menu”。
- 一个标为“Close”的按钮。
来理解一下用到的语法。 有许多种类的控件:文本框、列表、检索图、滑块等等。 可以在这里找到关于 XML 控件的完整参考说明:
- 我们为“Close”按钮添加一个背景图。 把下列 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>
按钮拥有不同的状态(mouseOver、selected、disabled)。 你可以为每种状态设置不同的图片。 你还能改变与按钮互动时的游标图片。
- 保存文件并重启 Play-The-Game 模式。 “Quit”按钮现在看起来像这样:
如果你将鼠标移到按钮上,你会看到按钮和鼠标的外观都发生了改变。 在你点击它的时候同样会变化。
- 现在你可以尝试在 XML 改变或添加控件。
恭喜!
你已经成功地在 Vision 中修改了 GUI 布局!
为关闭按钮添加功能
现在我们想为新按钮添加一些功能。 如果用户点击了它,我们希望关闭对话框。
首先我们创建一个新的脚本文件来控制对话框。 来到 vForge 中的 Script 面板并在“Dialogs”文件夹中创建一个新的脚本,命名为“MainMenu.lua”。 添加下列代码:
function OnItemClicked(self, item, buttons, x, y)
if (item:GetID() == GUI:GetID("QUIT")) then
self:SetVisible(false)
GUI:SetCursorVisible(false)
end
end
这个回调函数会在你每次点击对话框中的按钮时被调用。 Item::GetID 会返回按钮在 MainMenuLUA.xml 中定义的参数 ID。 所以当我们的按钮被点击时,我们将对话框隐藏。这里上下文中的“self”即代表对话框。 我们也同时隐藏游标。
最后我们需要将对话框 xml 和新建的脚本关联。 为此,请
- 打开“Dialogs”文件夹中的 MainMenuLUA.xml。
- 在对话框标记里加入如下 xml 代码
<DIALOG class="VDialog" name="MainMenu" fullscreen="FALSE" size="300,140" startPosition="ScreenCenter">
<script filename="MainMenu.lua" />
如果你现在运行 Play-The-Game 模式,你能够通过点击“Clost”按钮关闭对话框。
通过 GUI 控制场景元素
最后这章我们会演示如何通过勾选框来控制一个场景元素。 我们希望在清除选择框的时候关闭一个光源。 所以首先在 MainMenuLUA.xml 中添加一个勾选框:
<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>
在你运行 Play-The-Game 模式后会看到这样的对话框:
然后我们在场景中添加一个动态光源用来开关。
来到 Shapes Creator 面板,将 “Lights (Dynamic - Omni Light)”图形拖拽到场景中。
将光源移到一个你可以看到的地方。 然后到新光源的属性处修改颜色,比如绿色。之后在 ObjectKey 属性处输入字符串“switchlight”。 我们稍后会在 Lua 脚本中使用 ObjectKey 来获得光源。
最后,让我们在 vForge 脚本面板中扩展“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
如你所见,现在我们检查 ID 为“CHECKBOX1”的勾选框按钮是否被按下。 如果是,那么我们通过函数 Game:GetLight("switchlight") 获得光源存放在一个本地变量上。 “switchlight”是先前我们赋给动态光的 ObjectKey。 如果我们的光源可见,那么将其隐藏。 如果隐藏了,那么将其设为可见。
现在开始 Play-The-Game 模式。 你可以通过对话框中的勾选框来开关光源。
总结:
你已经成功完成了通过 Lua 控制 GUI 的教程。 但是请牢记,如果你需要诸如添加动态文字等高级 GUI 功能的话,应该使用 C++ 来创建 UI。 如果你对此感兴趣,请阅读 C++ GUI 课程。