第11章 向XML窗体中添加行为
我们现在已经创建了窗体、图形以及字体,并能对窗体的大小和位置进行设置,但是这些窗体都是静态的,不能同用户进行交互,或对任何游戏事件进行响应。本章将讨论XML模板,并且开始向XML窗体中添加动态行为。本章仅简单介绍如何添加行为,详细介绍要在第31章进行。
通过游戏事件,用户界面随着游戏状态的改变而改变。在这个过程中游戏可以通过窗体脚本与用户进行交互。
每个用于创建用户界面的窗体都具有特定类型的行为,它们可以实现响应,从而使界面真正变得具有交互性。
游戏事件是指游戏当中发生的各种事情,这些事情通常是游戏中的各种状态发生了改变。例如,当某个单位(团队中小队中的一个成员,或者是你选中的目标,无论是怪还是队友)生命值发生改变时,就会触发一个事件:UNIT_HEALTH。
如果你希望在某事件发生时去做一些事情(例如当队友血量过低时发出一个警告声),我们就必须使用:RegisterEvent()方法进行一个注册,这会使得每次事件触发时就调用<OnEvent>脚本。
每个窗体可以根据需要注册任意多的事件,但仅能够有一个 <OnEvent>脚本。游戏会将事件名称都发送到该处理模块,然后再根据不同的事件进行响应。
任何具有enableMouse属性的窗体都可以使用自定义的脚本对<OnEnter>和<OnLeave>行为进行响应。(默然说话:OnEnter就是鼠标进入事件,它在鼠标移动到一个窗体上被触发,OnLeave是鼠标离开事件,它在鼠标离开一个窗体上被触发)下面的代码是一个窗体的XML定义,其对这些行为进行了响应;它们应当位于WowXMLExample.xml的<Ui>节中:
<Framename="EnterLeaveTest" parent="UIParent">
<Size x="100" y="100" />
<Anchors>
<Anchor point="CENTER"relativePoint="CENTER" relativeTo="UIParent" />
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentIcon"file="Interface\Icons\Spell_ShadowWordPain" setAllPoints="true"/>
</Layer>
</Layers>
<Scripts>
<OnEnter>
ChatFrame1:AddMessage("++ 进入窗体:" .. self:GetName())
</OnEnter>
<OnLeave>
ChatFrame1:AddMessage("-- 离开窗体:" .. self:GetName())
</OnLeave>
</Scripts>
</Frame>
<Scripts>专门用来进行了事件响应代码的编写。如果你将这个插件加载,你会在屏幕的中央看到一个窗体,它的图标是“暗言术:痛”,如果你把鼠标移动到这个窗体上,你会看到聊天窗口会输出一句话:“++进入窗体:EnterLeaveTest”,如果移出来,则会看到:“—离开窗体:EnterLeaveTest”。
在XML中定义的每个窗体都可以拥有一个<OnLoad>脚本,并在窗体最初创建时执行。这个脚本通常用于注册事件和其他的初始化行为。脚本处理模块被调用时,伴随着表示窗体本身的self变量。下面的XML可以用于注册UNIT_HEALTH事件:
<OnLoad>
self:RegisterEvent("UNIT_HEALTH")
</OnLoad>
大多数事件的响应代码都应该放在OnEvent元素里。我们可以使用一系列判断语句,来完成对不同事件的响应处理。下面是一断模拟代码:
functionOnEvent(self,event,…)
if event == “UNIT_HEALTH” then
--这里写响应生命变动的代码
elseif event == “UNIT_MANA” then
--这里写响应法师值变动的代码
end
end
对于各种不同的事件,它们会有各种不同的参数,请参考第30章的事件列表。
下面是测试事件的注册和响应的代码:
<Scripts>
<OnLoad>
self:RegisterEvent("UNIT_HEALTH")
</OnLoad>
<OnEvent>
local unit=...
ChatFrame1:AddMessage("UNIT_HEALTH - unit=" .. unit)
</OnEvent>
</Scripts>
UNIT_HEALTH事件仅接收一个参数,即生命值受到影响的单位。由于OnEvent处理模块使用Lua的变量机制来传入变量,因此我们将“…”指定到局部变量,以使得我们可以得到unit这个参数并进行输出。这段代码在窗体发现单位的血量发生变化时就会触发,在聊天窗体里打出一句话。
按钮及复选按钮可以借助<OnClick>脚本响应对按钮的单击。本函数按受3个参数:
self——被单击的按钮
button——进行单击的鼠标按键
down——鼠标单击的方向
魔兽世界总共可以识别5种不同的鼠标按键:左键(LeftButton)、右键(RightButton)、中键(MiddleButton)、按键4(Button4)和按键5(Button5)。此外,游戏可以区分单击动作中鼠标按下和放开。默认情况下,按键仅接受LeftButtonUp事件,即左键的鼠标放开动作。这一点可以使用“:RegisterForClicks()”方法进行改变。
想要注册左击和右击,并且同时能接受按下和放开事件,您可以在<OnLoad>脚本中调用下面的代码:
self:RegisterForClicks(“LeftButtonUp”,”LeftButtonDown”,”RightButtonUp”,”RightButtonDown”)
注册一个按钮单击最简单的方法是在RegisterForClicks()方法中使用”AnyUp”和”AnyDown”虚拟按键。下面的代码是一个XML定义的例子,展示了一个<OnClick>脚本。
<Buttonname="OnClickTest" parent="UIParent">
<Size x="100" y="100" />
<Anchors>
<Anchorpoint="CENTER" relativePoint="CENTER"relativeTo="UIParent" />
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentIcon"file="Interface\Icons\Spell_Shadow_ShadowWordPain"setAllPoint="true" />
</Layer>
</Layers>
<Scripts>
<OnLoad>
self:RegisterForClicks("AnyUp","AnyDown")
</OnLoad>
<OnClick>
ChatFrame1:AddMessage(self:GetName() .." - Button: " .. tostring(button) .. "Down:" ..tostring(down))
</OnClick>
</Scripts>
</Button>
这是一个特殊的脚本,它在每次魔兽世界客户端重新绘制一个窗体时调用。因此,当窗体被显示(不一定被玩家看到)时触发。一个窗体可以没有纹理或可视元素,但OnUpdate脚本仍可存在,来完成一些阶段性的任务,这个脚本将在第18章创建MapZoomOut插件时使用,并用来创建一个管理排序的时间器。
表11-1 窗体脚本
脚本 | 描述 | 适用的窗体 |
OnChar(self,text) | 当窗体enableMouse属性为true时,所有的键盘输入将使用这个脚本发送到窗体中,第二个参数为从键盘接收到的文本 | 所有窗体类型 |
OnClick(self,button,down) | 当鼠标单击到按钮上时,该脚本被调用,第二个参数为鼠标所按的键(LeftButton,RightButton),第三个参数为触发时鼠标键的状态,true表示被按下 | 按钮、复选按钮 |
OnDoubleClick(self,button) | 当鼠标双击到一个按钮时调用此脚本。鼠标按下不能触发此事件,只能在鼠标放开的时候会触发。 | 按钮、复选按钮 |
OnDragStart(self,button) OnDragStop(self,button) | 窗体拖拉事件,在用户按住鼠标键同时移动鼠标时触发OnDragStart事件,释放鼠标时触发OnDragStop事件。第2个参数是鼠标键的名称列表,如LeftButton,RightButton等。可以调用self:RegisterForDrag()来注册拖拽事件。 | 所有窗体类型 |
OnEnter(self,motion) OnLeave(self,motion) | 当一个窗体被设定为接收鼠标事件时,OnEnter在鼠标移动到窗体里时触发,OnLeave在鼠标移动到窗体外时触发。 | 所有窗体类型 |
OnHide(self) OnShow(self) | OnHide在窗体被隐藏时触发,OnShow在窗体被显示时触发,隐藏的窗体可以继续接收事件。 | 所有窗体类型 |
PreClick(self,button,down) PostClick(self,button,down) | 预单击 后单击(什么屁话!) | 按钮,复选按钮 |
您在魔兽世界中所创建的每个带名称的窗体可以通过Lua脚本接口进行访问,您可以直接与它进行交互。调用它们的方法,修改它们的属性。包含所有窗体类型及相关可用方法的完整列表请参阅第31章。
表11-2窗体、纹理和字体字符串的常用方法
方法 | 描述 |
Object:GetAlpha() | 得到给定对象当前的透明度值 |
Object:GetName() | 得到给定对象的名称,若没有名称则返回nil |
Object:GetObjectType() | 返回包含对象类型的字符串 |
Object:IsObjectType(“type”) | 若对象为给定的类型则返回1,否则返回nil |
Object:SetAlpha(alpha) | 设定给定对象的透明度。alpha应当为一个介于0.0~1.0之间的值 |
Object:Show() | 显示对象。这可能不会使其显示在屏幕上,例如,若其没有被放置,或是其父对象被隐藏。 |
Object:Hide() | 隐藏对象 |
Object:IsShown() | 若对象正在被显示则返回1,否则返回nil。这并不意味着其一定在屏幕上可见,仅能说明对象的Object:Hide()没有被调用。 |
Object:IsVisible() | 若对象及其父对象、祖父对象等祖先均被显示,则返回1 |
关于窗体方法有很多,请参阅第31章。
魔兽世界提供了几百个不同的模板来供默认用户界面使用,这样,你开发的用户界面与别人开发的用户界面很容易就能统一一致。
模板最大的作用不是体现在创建它的时候,而是体现在当我们需要进行修改的时候,如果不使用模板,我们需要对界面进行的相同修改可能就需要重复几十甚至上百次,而使用了模板,我们只需要修改模板就可以了。
创建一个XML模板需要在name属性中提供模板名称,并将virtual属性设置为true。其它和您编辑一个窗体的设置是一样的。
在您的WowXMLExample.xml文件的<Ui>节中创建下面的XML定义:
<Buttonname="IconTestTemplate" virtual="true">
<Size x="32" y="32" />
<Layers>
<Layer level="OVERLAY">
<Texture name="$parentIcon"
file="Interface\Icons\Speel_Shadow_ShadowWordPain"setAllPoints="true" />
</Layer>
</Layers>
<Scripts>
<OnLoad>
self.Icon=getglobal(self:GetName() .."Icon")
</OnLoad>
<OnEnter>
self.Icon:SetDesaturated(true)
</OnEnter>
<OnLeave>
self.Icon:SetDesaturated(nil)
</OnLeave>
<OnClick>
ChatFrame1:AddMeessage("You clickedon " .. self:GetName())
</OnClick>
</Scripts>
</Button>
这里创建了一个按钮,它会显示暗言术:痛的图标,当鼠标移动到上面时,图标会变成灰度(OnEnter中定义的内容),当鼠标移动开的时候,图标双恢复彩色(OnLeave中定义的内容),如果你单击了这个按钮,会在聊天窗体中显示一句话(OnClick定义的内容)。
现在我们使用刚刚定义的模板来创建四个按钮:(同样位于<Ui>节)
<Buttonname="IconTest1" inherits="IconTestTemplate"parent="UIParent">
<Anchors>
<Anchor point="BOTTOMRIGHT"relativePoint="CENTER" relativeTo="UIParent" />
</Anchors>
</Button>
<Button name="IconTest2"inherits="IconTestTemplate" parent="UIParent">
<Anchors>
<Anchor point="BOTTOMLEFT"relativePoint="CENTER" relativeTo="UIParent" />
</Anchors>
</Button>
<Button name="IconTest3"inherits="IconTestTemplate" parent="UIParent">
<Anchors>
<Anchor point="TOPLEFT"relativePoint="CENTER" relativeTo="UIParent" />
</Anchors>
</Button>
<Button name="IconTest4"inherits="IconTestTemplate" parent="UIParent">
<Anchors>
<Anchor point="TOPRIGHT"relativePoint="CENTER" relativeTo="UIParent" />
</Anchors>
</Button>
魔兽世界提供了几百个在游戏中很有用的用户界面模板。本节将介绍使用最频繁的几个模板。
表11-3使用最频繁的模板
模板 | 描述 |
UIPanelButtonTemplate | 在游戏中用于游戏按钮 |
UIPanelButtonTemplate2 | 与UIPanelButtonTemplate用途相同,更易于调整尺寸。 |
UIPanelCloseButton | 用于许多用户界面创建简单的“关闭”按钮 |
InputBoxTemplate | 默然用户界面用它来做聊天窗体,插件用它来输入文本 |
UICheckButtonTemplate | 允许您创建一个复选按钮。包括显示的提示功能的文字 |
TabButtonTemplate | 可用于在一个窗口的顶端或底端创建带标签的按钮。它可以较好地整合到默认UI样式中 |
GameMenuButtonTemplate | 具有指定的尺寸,这是由于其被用于当您按Esc键时显示的菜单 |
UIRadioButtonTemplate | 可用于创建简单的选项按钮。 |
OptionsSliderTemplate | 为您提供一个主标签,同时提供了一些子标签来表示最大值和最小值。有个滑块可以用来在一个范围内选择数值。 |