http://blog.csdn.net/tcxxs/category/148474.aspx1、这是我分析WOW原始UI代码后,对一些比较关键的部分,记录下来的
2、文章里面如果有什么纰漏,希望大家毫不客气的提出来,我一定查究!
3、关于基础问题可以参考
WOW UI
《UI制作入门》http://www.pcgames.com.cn/netgames/zhuanti/wow/expert/Ui.htm
《WOW UI定制入门》http://202.113.13.169/site/mybbs/read.php?tid=33
《WOW插件制作指南》http://www.cnblogs.com/bluefee/archive/2005/04/14/137217.html
《ADDONS编写普及》http://wowbbs.game.mop.com/viewthread.php?tid=216755&extra=page%3D1
《动手写个属于自己的UI》http://wowbbs.game.mop.com/viewthread.php?tid=149814&fpage=1&highlight=
XML
《XML初学进阶》http://www.chinausd.com/code/code.asp?id=173/5058
《XMLSpy 2005 Enterprise Edition》http://www.altova.com/download_spy_enterprise.html
Lua
《Lua5.0参考手册中文版》http://www.cnblogs.com/bluefee/archive/2005/04/15/138576.html
《Lua 程序设计初步》http://bbs.battlecn.net/read.php?tid=541871&fpage=1
《通过例子学习Lua》http://www.wowtc.com/bbs/read.php?tid=4999&fpage=2
《Programming in LUA中文版》http://www.wowtc.com/bbs/read.php?tid=4998&fpage=2
《LuaEdit v2.5》http://luaforge.net/projects/luaedit/
4、关于如何提取MPQ文件,如何查看BLP图像,可以参考
《WoW Working Link》http://www.fukt.bth.se/%7Ek/wow/stuff/howto-extract-interface-files.txt
《Win MPQ》http://wow.duowan.com/2005-05-16/007R/26857843.html
《Win BLP Viewer》http://gamedown.yesky.com/game/108/108805.html
5、关于查询资料可以参考
《WoW Wiki》http://www.wowwiki.com/Interface_Customization/
《WOW APIs》http://www.cnblogs.com/bluefee/archive/2005/04/12/136270.html
《UI&Macro Forum》http://forums.worldofwarcraft.com/board.aspx?fn=wow-interface-customization
6、如果该问题是可以类推,或是从上下文能马上理解,或是从字面就知道含义的我就不罗嗦了
7、对于相同的问题我一般只分析一次,或是简要的提示一下,具体内容可以参考我以前的分析
8、如果你对自己查找资料的能力感到抱歉,可以E-mail向我询问,我会努力帮助你
9、联系方式E-mail: asdic.xxs@gmail.com Blog: blog.csdn.net/tcxxs QQ: 35548917
10、做人要厚道,转载请注明出处!
--------------------------------------------------
正式开始:
1、版本:1.7.1 (4659)
2、这次我写的是ActionbuttonTemplate.xml,ActionBarFrame.xml和ActionButton.lua
他们是动作按钮的基础UI,也是大家比较关心的一部分,在Interface/FrameXML里面
3、这次分析用到的名词解释:
【模板】学过C++语言的人都知道虚函数,实际上是一个道理,只是作为子代继承的规范,不可创建实例
【栅格】一个用来放置图标的格子,默认为无图标时隐藏,当然你也可以显示它
【额外栅格】包括了战士姿态,德鲁依外形,盗贼潜行的栅格
【栅格ID】每个栅格都有对应的ID,是该栅格的唯一标示
【图标】每个技能和物品,包括交易技能,食物,宏等都有一个可以拖动的图标
【动作键】当把图标放置到栅格上时,这个整体就叫动作键
【额外动作键】当把图标放置到额外栅格上时,这个整体就叫额外动作键
【动作条】一般12个栅格组成一排或者一列,称这个为动作条
【额外动作条】由12个额外栅格组成一排或者一列,称这个为额外动作条
【动作条ID】在默认动作条中每个动作条都有页码,是这个动作条的唯一标示
这里解释一下各个动作条的位置,主动作条包括1,2页
然后右边1,右边2,右下,左下依次为3到6页,栅格ID排列如图
61-72(左下)49-60(右下)37 25
(右边2) I I (右边1)
1-12(主AB)13-24(2页) 48 36
这里注意一个问题,为什么有的UI可以实现96个(FB,DUF等)或者更多呢
这是因为额外栅格的存在,这些UI把空闲的额外栅格加以利用罢了
调用这些额外栅格的动作键应该用其对应的函数
【闪动】当执行自动攻击或者自动射击技能时,改动作键就处于闪动状态
【CD】CoolDown的简写
【信息提示】即GameTooltip,当鼠标指向某个东西时显示的提示信息
【光环】包括buff,debuff,物品附加属性等
【arg1..N】arg为事件触发是传入的参数,可以为0到多个
--------------------------------------------
源代码及注释
-----------------------ActionButtonTemplate.xml
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<CheckButton name="ActionButtonTemplate" virtual="true">
【动作键】【模板】
<Size>
<AbsDimension x="36" y="36"/>
</Size>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentIcon"/>
背景层放置【图标】
</Layer>
<Layer level="ARTWORK">
层的从下到上为:BackGround,ArtWork,OverLay
<Texture name="$parentFlash" file="Interface\Buttons\UI-QuickslotRed" hidden="true"/>
【闪动】效果的纹理
<FontString name="$parentHotKey" inherits="NumberFontNormalSmallGray" justifyH="RIGHT">
该【动作键】的快捷键信息
<Size>
<AbsDimension x="32" y="10"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="2" y="-2"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT">
该【动作键】数量信息
<Anchors>
注意,这里没有Size标签,所以它为自动大小
<Anchor point="BOTTOMRIGHT">
<Offset>
<AbsDimension x="-2" y="2"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
</Layer>
<Layer level="OVERLAY">
<FontString name="$parentName" inherits="GameFontHighlightSmallOutline">
该【动作键】名字,例如:宏的名字
<Size>
<AbsDimension x="36" y="10"/>
</Size>
<Anchors>
<Anchor point="BOTTOM">
<Offset>
<AbsDimension x="0" y="2"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<Model name="$parentCooldown" inherits="CooldownFrameTemplate"/>
直接应用【CD】模板,没有测试过,还望高人赐教,或者等我以后试
</Frames>
<NormalTexture name="$parentNormalTexture" file="Interface\Buttons\UI-Quickslot2">
【图标】边框纹理,如果该【栅格】已放置【图标】,则显示这个纹理
若没有放置,则显示UI-Quickslot,它比UI-Quickslot2稍微小点
<Size>
<AbsDimension x="64" y="64"/>
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset>
<AbsDimension x="0" y="-1"/>
立体效果,而且UI-Quickslot的显示位置也依赖UI-Quickslot2
但是【图标】的实际放置位置却并不依赖这个位置,由BackGround层决定
</Offset>
</Anchor>
</Anchors>
</NormalTexture>
<PushedTexture file="Interface\Buttons\UI-Quickslot-Depress"/>
点击【动作键】时的纹理
<HighlightTexture alphaMode="ADD" file="Interface\Buttons\ButtonHilight-Square"/>
鼠标经过【栅格】时的纹理
<CheckedTexture alphaMode="ADD" file="Interface\Buttons\CheckButtonHilight"/>
等待施法时【栅格】的纹理,例如:你点击加血法术到选择目标那段时间显示
</CheckButton>
</Ui>
------------------------ActionBarFrame.xml
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="ActionButton.lua"/>
<CheckButton name="ActionBarButtonTemplate" inherits="ActionButtonTemplate" virtual="true">
<Scripts>
<OnLoad>
ActionButton_OnLoad();
</OnLoad>
<OnEvent>
ActionButton_OnEvent(event);
</OnEvent>
<OnClick>
if ( IsShiftKeyDown() ) then
安住shift再点【动作键】,即拖拉【图标】
PickupAction(ActionButton_GetPagedID(this));
鼠标吸附该【图标】
else
否则执行该【动作键】命令
MacroFrame_EditMacro();
UseAction(ActionButton_GetPagedID(this), 1);
UseAction(slot [,checkCursor] [,onSelf])函数
slot参数为该【动作键】ID号
checkCursor参数为是否在其他事件中返回是鼠标点击,0或者1
onSelf参数为是否对自己施法,0或者1
end
ActionButton_UpdateState();
点击后应该更新【动作键】状态
</OnClick>
<OnDragStart>
if ( LOCK_ACTIONBAR ~= "1" ) then
如果【动作键】并未设定为锁定
PickupAction(ActionButton_GetPagedID(this));
ActionButton_UpdateState();
end
</OnDragStart>
<OnReceiveDrag>
if ( LOCK_ACTIONBAR ~= "1" ) then
PlaceAction(ActionButton_GetPagedID(this));
PlaceAction,放下鼠标上吸附的【动作键】
注意,这里并不要求一定要放在栅格上,因为你可以摧毁一个【动作键】
ActionButton_UpdateState();
end
</OnReceiveDrag>
<OnEnter>
ActionButton_SetTooltip();
经过【动作键】时,显示【信息提示】
</OnEnter>
<OnLeave>
this.updateTooltip = nil;
GameTooltip:Hide();
</OnLeave>
<OnUpdate>
ActionButton_OnUpdate(arg1);
更新【闪动】效果
</OnUpdate>
</Scripts>
</CheckButton>
下面定义了主【动作条】
<CheckButton name="ActionButton1" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="1">
MainMenuBarArtFrame,即默认最下面的一条工具栏,包括了主【动作条】,人物工具条,背包
但是注意,并不包括两旁的2只鹰的纹理
<Anchors>
<Anchor point="BOTTOMLEFT">
<Offset>
<AbsDimension x="8" y="4"/>
左下和右下的【动作条】都依据主【动作条】的位置
【信息提示】和【额外栅格】并不依据这个偏移,但是它会根据左下和右下【动作条】的出现而更改高度
若仅改变该偏移,则如果该人物有【额外栅格】,则人物的主【动作条】将会在原位又出现一个
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton2" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="2">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton1" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton3" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="3">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton2" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton4" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="4">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton3" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton5" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="5">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton4" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton6" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="6">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton5" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton7" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="7">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton6" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton8" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="8">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton7" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton9" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="9">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton8" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton10" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="10">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton9" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton11" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="11">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton10" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<CheckButton name="ActionButton12" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="12">
<Anchors>
<Anchor point="LEFT" relativeTo="ActionButton11" relativePoint="RIGHT">
<Offset>
<AbsDimension x="6" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
<Button name="ActionBarUpButton" parent="MainMenuBarArtFrame">
主【动作条】位置上的上翻页按钮
<Size>
<AbsDimension x="32" y="32"/>
</Size>
<Anchors>
<Anchor point="CENTER" relativeTo="MainMenuBarArtFrame" relativePoint="TOPLEFT">
<Offset>
<AbsDimension x="522" y="-22"/>
</Offset>
</Anchor>
</Anchors>
<HitRectInsets>
<AbsInset left="6" right="6" top="7" bottom="7"/>
这个一直没有测试成功,还望高人指点迷津
</HitRectInsets>
<Scripts>
<OnLoad>
MainMenuBarPageNumber:SetText(CURRENT_ACTIONBAR_PAGE);
CURRENT_ACTIONBAR_PAGE,当前【动作条ID】
当你显示了其他【动作条】如:左下【动作条】,那么它将不会在翻页中重复出现
this:RegisterEvent("ACTIONBAR_PAGE_CHANGED");
当主【动作条】的页码改变时触发
</OnLoad>
<OnEvent>
if ( event == "ACTIONBAR_PAGE_CHANGED" ) then
MainMenuBarPageNumber:SetText(CURRENT_ACTIONBAR_PAGE);
end
</OnEvent>
<OnClick>
ActionBar_PageUp();
PlaySound("UChatScrollButton");
PlaySound(SoundName),播放一个WOW内置的声音
SoundName为内置参数的名字,可以参考下面地址
http://www.wowwiki.com/API_PlaySound
注意,你不要试图在MPQ文件中找到这个名字
</OnClick>
</Scripts>
<NormalTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Up"/>
<PushedTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Down"/>
<DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Disabled"/>
被锁定时的纹理,未测试成功,望高人指点一二
<HighlightTexture alphaMode="ADD" file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Highlight"/>
</Button>
<Button name="ActionBarDownButton" parent="MainMenuBarArtFrame">
<Size>
<AbsDimension x="32" y="32"/>
</Size>
<Anchors>
<Anchor point="CENTER" relativeTo="MainMenuBarArtFrame" relativePoint="TOPLEFT">
<Offset>
<AbsDimension x="522" y="-42"/>
</Offset>
</Anchor>
</Anchors>
<HitRectInsets>
<AbsInset left="6" right="6" top="7" bottom="7"/>
</HitRectInsets>
<Scripts>
上翻中已经注册并处理了事件,这里不重复
<OnClick>
ActionBar_PageDown();
PlaySound("UChatScrollButton");
</OnClick>
</Scripts>
<NormalTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Up"/>
<PushedTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Down"/>
<DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Disabled"/>
<HighlightTexture alphaMode="ADD" file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Highlight"/>
</Button>
</Ui>
------------------------ActionButton.lua
CURRENT_ACTIONBAR_PAGE = 1;
当前【动作条ID】
NUM_ACTIONBAR_PAGES = 6;
【动作条ID】总数
NUM_ACTIONBAR_BUTTONS = 12;
每个【动作条】的【动作键】数
ATTACK_BUTTON_FLASH_TIME = 0.4;
【闪动】效果时间间隔,为0.4S
BOTTOMLEFT_ACTIONBAR_PAGE = 6;
初始左下【动作条ID】
BOTTOMRIGHT_ACTIONBAR_PAGE = 5;
初始右下【动作条ID】
LEFT_ACTIONBAR_PAGE = 4;
初始右边2【动作条ID】
RIGHT_ACTIONBAR_PAGE = 3;
初始右边1【动作条ID】
-- Table of actionbar pages and whether they're viewable or not
VIEWABLE_ACTION_BAR_PAGES = {1, 1, 1, 1, 1, 1};
初始化为每页【动作条】都能够显示,0为隐藏
function ActionButtonDown(id)
实现按下【动作键】
if ( BonusActionBarFrame:IsVisible() ) then
如果是【额外动作键】
local button = getglobal("BonusActionButton"..id);
if ( button:GetButtonState() == "NORMAL" ) then
若未按下
button:SetButtonState("PUSHED");
end
return;
该函数用if-else是同样的
end
local button = getglobal("ActionButton"..id);
if ( button:GetButtonState() == "NORMAL" ) then
button:SetButtonState("PUSHED");
end
end
由上下2个函数可以看出,暴雪对【动作键】和【额外动作键】同样对待
这个也是其他UI可以利用【额外栅格】的基础
function ActionButtonUp(id, onSelf)
if ( BonusActionBarFrame:IsVisible() ) then
local button = getglobal("BonusActionButton"..id);
if ( button:GetButtonState() == "PUSHED" ) then
button:SetButtonState("NORMAL");
-- Used to save a macro
MacroFrame_EditMacro();
UseAction(ActionButton_GetPagedID(button), 0);
if ( IsCurrentAction(ActionButton_GetPagedID(button)) ) then
IsCurrentAction,等待施法,并不是正在吟唱
button:SetChecked(1);
设定该【动作键】正处于等待状态
else
button:SetChecked(0);
end
end
return;
end
local button = getglobal("ActionButton"..id);
if ( button:GetButtonState() == "PUSHED" ) then
button:SetButtonState("NORMAL");
-- Used to save a macro
MacroFrame_EditMacro();
UseAction(ActionButton_GetPagedID(button), 0, onSelf);
if ( IsCurrentAction(ActionButton_GetPagedID(button)) ) then
button:SetChecked(1);
else
button:SetChecked(0);
end
end
end
function ActionBar_PageUp()
CURRENT_ACTIONBAR_PAGE = CURRENT_ACTIONBAR_PAGE + 1;
local nextPage;
for i=CURRENT_ACTIONBAR_PAGE, NUM_ACTIONBAR_PAGES do
if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then
如果该页能显示
nextPage = i;
break;
end
end
if ( not nextPage ) then
如果没有找到能够显示的下一页
CURRENT_ACTIONBAR_PAGE = 1;
else
CURRENT_ACTIONBAR_PAGE = nextPage;
end
ChangeActionBarPage();
这个函数变换将当主【动作条】变换到CURRENT_ACTIONBAR_PAGE指向的【动作条】
end
function ActionBar_PageDown()
CURRENT_ACTIONBAR_PAGE = CURRENT_ACTIONBAR_PAGE - 1;
local prevPage;
for i=CURRENT_ACTIONBAR_PAGE, 1, -1 do
if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then
prevPage = i;
break;
end
end
if ( not prevPage ) then
for i=NUM_ACTIONBAR_PAGES, 1, -1 do
把“1”换成“CURRENT_ACTIONBAR_PAGE+1”也是可以的
把这个for循环对比ActionBar_PageUp的同一地方
可见,暴雪员工相当的肯定在上翻的时候第1页是可以显示的
而在下翻的时候显得信心不足,还重复检查了一次NUM_ACTIONBAR_PAGES到CURRENT_ACTIONBAR_PAGE
这是因为左下、右下AB的出现只是修改5,6页的可见性,并不影响1页的可见性
所以在下翻的时候需要对1到6页均做可见性检查
但是,重复检查的区间的确是多余的,估计是暴雪员工偷懒
因为“1”比“CURRENT_ACTIONBAR_PAGE+1”要好写得多
if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then
prevPage = i;
break;
end
end
end
CURRENT_ACTIONBAR_PAGE = prevPage;
ChangeActionBarPage();
end
function ActionButton_OnLoad()
this.showgrid = 0;
显示空【栅格】的标志
this.flashing = 0;
处于【闪动】的标志
this.flashtime = 0;
【闪动】时间间隔计算的中间量
ActionButton_Update();
this:RegisterForDrag("LeftButton", "RightButton");
对this所指向的窗体注册鼠标拖拉行为,参数至少一个,也可以注册多个
参数为LeftButton,RightButton,表示使用某个鼠标键执行
this:RegisterForClicks("LeftButtonUp", "RightButtonUp");
对this所指向的窗体注册鼠标点击行为,参数至少一个,也可以注册多个
参数为LeftButtonDown,LeftButtonUp,RightButtonDown,RightButtonUp
注意,在OnClick标签中传入的arg1参数只返回LeftButton或者RightButton
this:RegisterEvent("PLAYER_ENTERING_WORLD");
this:RegisterEvent("UPDATE_BONUS_ACTIONBAR");
当【额外栅格】更新时触发
this:RegisterEvent("ACTIONBAR_SHOWGRID");
当拖拉【图标】时触发,arg1为LeftButton或者RightButton
this:RegisterEvent("ACTIONBAR_HIDEGRID");
当停止拖拉【图标】时触发
this:RegisterEvent("ACTIONBAR_PAGE_CHANGED");
this:RegisterEvent("ACTIONBAR_SLOT_CHANGED");
当【栅格】内容变更时触发,arg1为变更【栅格ID】
this:RegisterEvent("ACTIONBAR_UPDATE_STATE");
当【栅格】状态更新时触发,包括了【CD】和可用性鉴定
但是不包括自动攻击和自动射击事件
arg1为鼠标LeftButton,RightButton,也可能为nil
this:RegisterEvent("ACTIONBAR_UPDATE_USABLE");
当更新【图标】可用性后触发
this:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
当更新【CD】后触发
当【CD】开始的时候,arg1返回使用的鼠标按钮LeftButton或者RightButton
当【CD】结束的时候,arg1返回nil
this:RegisterEvent("UPDATE_INVENTORY_ALERTS");
当变更装备时或者经过一定时间后触发
this:RegisterEvent("PLAYER_AURAS_CHANGED");
当玩家【光环】改变时触发,包括了【光环】的消失和出现
注意,属性完全相同【光环】重复释放并不能触发该事件
this:RegisterEvent("PLAYER_TARGET_CHANGED");
当玩家的目标变更时触发,包括取消和选定目标
arg1为该目标持续时间,单位分钟,小数保留3位
this:RegisterEvent("UNIT_AURASTATE");
当某单位短时间【光环】改变时触发,需进一步测试
this:RegisterEvent("UNIT_INVENTORY_CHANGED");
当玩家装备变更时或者当观察玩家装备并发生装备变更时触发
this:RegisterEvent("CRAFT_SHOW");
this:RegisterEvent("CRAFT_CLOSE");
工艺窗口的显示与关闭,arg1为鼠标点击键
this:RegisterEvent("TRADE_SKILL_SHOW");
this:RegisterEvent("TRADE_SKILL_CLOSE");
交易技能制作物品窗口的显示与关闭,arg1为鼠标点击键
this:RegisterEvent("UNIT_HEALTH");
当任何一个单位的血量发生变化时触发,arg1参数为该单位ID
player,pet,target,mouseover,party1..4,partypet1..4,raid1..40,raidpet1..40,npc
注意,该事件拥有很高的优先级,特别当参数为player时
this:RegisterEvent("UNIT_MANA");
当任何一个单位的魔法量发生变化时触发,arg1参数为该单位ID
this:RegisterEvent("UNIT_RAGE");
当任何一个单位的怒气值发生变化时触发,arg1参数为该单位ID
this:RegisterEvent("UNIT_FOCUS");
当任何一个单位的焦距值发生变化时触发,arg1参数为该单位ID
注意,该事件实际上已经废除,因为现在猎人使用MANA,而不是FOCUS
this:RegisterEvent("UNIT_ENERGY");
当任何一个单位的能量发生变化时触发,arg1参数为该单位ID
this:RegisterEvent("PLAYER_ENTER_COMBAT");
当玩家进入自动攻击状态时触发,自动射击不包括在内
注意,仅当你使用自动攻击时触发该事件
使用其他任何技能或者攻击行为都不可触发
this:RegisterEvent("PLAYER_LEAVE_COMBAT");
离开自动攻击状态或者死亡时触发
this:RegisterEvent("PLAYER_COMBO_POINTS");
当连击点变更时触发,arg1总返回player,而并不时连击点数
this:RegisterEvent("UPDATE_BINDINGS");
当快捷键更改时触发
this:RegisterEvent("START_AUTOREPEAT_SPELL");
当自动射击开始时触发,而不是自动攻击
this:RegisterEvent("STOP_AUTOREPEAT_SPELL");
离开自动射击状态或者死亡时触发
ActionButton_UpdateHotkeys();
end
function ActionButton_UpdateHotkeys(actionButtonType)
if ( not actionButtonType ) then
actionButtonType = "ACTIONBUTTON";
end
local hotkey = getglobal(this:GetName().."HotKey");
该对象在模板中为Fontstring
local action = actionButtonType..this:GetID();
actionButtonType,为该类命令的名字
this:GetID,得到该命令在该类中的ID号
注意,这2个字符串组成了最终的命令的名字
如NUMPAD2,NUMPAD为类型,2为ID
但是有些类型就一个命令无ID,如LEFT
hotkey:SetText(KeyBindingFrame_GetLocalizedName(GetBindingKey(action), "KEY_"));
GetBindingKey得到命令的快捷键名字,后面加上KEY_是为了显示命令的字串
例如:KEY_NUMPAD2就显示为“数字键盘2”
KeyBindingFrame_GetLocalizedName,由这个函数在快捷键窗口中显示该命令的快捷键
end
function ActionButton_Update()
-- Special case code for bonus bar buttons
-- Prevents the button from updating if the bonusbar is still in an animation transition
if ( this.isBonus and this.inTransition ) then
ActionButton_UpdateUsable();
ActionButton_UpdateCooldown();
return;
end
local icon = getglobal(this:GetName().."Icon");
local buttonCooldown = getglobal(this:GetName().."Cooldown");
local texture = GetActionTexture(ActionButton_GetPagedID(this));
if ( texture ) then
icon:SetTexture(texture);
icon:Show();
如果该【栅格】有【图标】,即若为【动作键】则显示
this.rangeTimer = TOOLTIP_UPDATE_TIME;
每隔TOOLTIP_UPDATE_TIME事件间隔更新一次距离信息
TOOLTIP_UPDATE_TIME为0.2S
this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");
-- Save texture if the button is a bonus button, will be needed later
if ( this.isBonus ) then
判断自己是否为【额外栅格】
this.texture = texture;
end
else
icon:Hide();
buttonCooldown:Hide();
this.rangeTimer = nil;
this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot");
getglobal(this:GetName().."HotKey"):SetVertexColor(0.6, 0.6, 0.6);
end
ActionButton_UpdateCount();
if ( HasAction(ActionButton_GetPagedID(this)) ) then
判断该【栅格】是否有【图标】,即是否为【动作键】
this:Show();
ActionButton_UpdateState();
ActionButton_UpdateUsable();
ActionButton_UpdateCooldown();
ActionButton_UpdateFlash();
elseif ( this.showgrid == 0 ) then
this:Hide();
else
这里表示,当该【栅格】没有【图标】
但是显示空【栅格】选项开启时,不显示公共CD效果
buttonCooldown:Hide();
end
if ( GameTooltip:IsOwned(this) ) then
判断该【动作键】是否拥有【信息提示】
ActionButton_SetTooltip();
else
this.updateTooltip = nil;
end
-- Update Macro Text
local macroName = getglobal(this:GetName().."Name");
macroName:SetText(GetActionText(ActionButton_GetPagedID(this)));
GetActionText返回宏的名字
end
function ActionButton_ShowGrid(button)
if ( not button ) then
button = this;
end
button.showgrid = button.showgrid+1;
getglobal(button:GetName().."NormalTexture"):SetVertexColor(1.0, 1.0, 1.0, 0.5);
SetVertexColor(R,G,B)这个函数需要注意,可能学过3D的都知道,这个是顶点着色,取值0到1小数
顶点着色并不是直接设置RGB的数值,而是在原有的RGB数值上乘以顶点着色指定的RGB百分比修正值
例如:一个色块RGB为50,100,30,如果你写入SetVertexColor(0.5,0,1),结果RGB为25,0,30
button:Show();
end
function ActionButton_HideGrid(button)
if ( not button ) then
button = this;
end
button.showgrid = button.showgrid-1;
if ( button.showgrid == 0 and not HasAction(ActionButton_GetPagedID(button)) ) then
把这里判断showgrid变量为0和这一对函数对showgrid的操作联系起来看
就像是用堆栈实现括号配对一样保证了显示和隐藏的规范
button:Hide();
end
end
function ActionButton_UpdateState()
if ( IsCurrentAction(ActionButton_GetPagedID(this)) or IsAutoRepeatAction(ActionButton_GetPagedID(this)) ) then
IsAutoRepeatAction,自动射击
IsAttackAction,自动攻击
this:SetChecked(1);
else
this:SetChecked(0);
end
end
function ActionButton_UpdateUsable()
注意,这个函数的主体是个技能按钮模板,所以针对的是一个【动作键】
所以,当你拖动某个【图标】时,其他【图标】并不会跟着更新
local icon = getglobal(this:GetName().."Icon");
模板中定义
local normalTexture = getglobal(this:GetName().."NormalTexture");
local isUsable, notEnoughMana = IsUsableAction(ActionButton_GetPagedID(this));
得到当前技能栅格的ID,这个是所有栅格ID号,包括73~96的
if ( isUsable ) then
是否在射程,当前在其他游戏规则中是否可用,是否在CD等
icon:SetVertexColor(1.0, 1.0, 1.0);
normalTexture:SetVertexColor(1.0, 1.0, 1.0);
elseif ( notEnoughMana ) then
是否足够魔法、怒气、能量
icon:SetVertexColor(0.5, 0.5, 1.0);
normalTexture:SetVertexColor(0.5, 0.5, 1.0);
else
icon:SetVertexColor(0.4, 0.4, 0.4);
这个是灰色效果,当你拖拉【图标】时,原【栅格】则为这个效果
normalTexture:SetVertexColor(1.0, 1.0, 1.0);
end
end
function ActionButton_UpdateCount()
local text = getglobal(this:GetName().."Count");
在模板中数量为Fontstring
if ( IsConsumableAction(ActionButton_GetPagedID(this)) ) then
判断是否改【栅格】的物品为消费品
text:SetText(GetActionCount(ActionButton_GetPagedID(this)));
else
text:SetText("");
end
end
function ActionButton_UpdateCooldown()
local cooldown = getglobal(this:GetName().."Cooldown");
在模板中该【CD】定义为一个Model
local start, duration, enable = GetActionCooldown(ActionButton_GetPagedID(this));
CooldownFrame_SetTimer(cooldown, start, duration, enable);
end
function ActionButton_OnEvent(event)
if ( event == "ACTIONBAR_SLOT_CHANGED" ) then
if ( arg1 == -1 or arg1 == ActionButton_GetPagedID(this) ) then
如果变更的【栅格】不明或者变更的【栅格】为自己则更新
ActionButton_Update();
end
return;
end
if ( event == "PLAYER_ENTERING_WORLD" or event == "ACTIONBAR_PAGE_CHANGED" ) then
总结起来是,当游戏环境有大的变化时,更新自己
ActionButton_Update();
return;
end
if ( event == "UPDATE_BONUS_ACTIONBAR" ) then
if ( this.isBonus ) then
ActionButton_Update();
end
return;
end
if ( event == "ACTIONBAR_SHOWGRID" ) then
ActionButton_ShowGrid();
return;
end
if ( event == "ACTIONBAR_HIDEGRID" ) then
ActionButton_HideGrid();
return;
end
if ( event == "UPDATE_BINDINGS" ) then
ActionButton_UpdateHotkeys();
return;
end
-- All event handlers below this line MUST only be valid when the button is visible
if ( not this:IsVisible() ) then
如果该【图标】不可见,那么直接返回,即下面的所有事件均要求该【图标】可见,即应该为一个【动作键】
return;
end
if ( event == "UNIT_HEALTH" or event == "UNIT_MANA" or event == "UNIT_RAGE" or event == "UNIT_FOCUS" or event == "UNIT_ENERGY" ) then
if ( arg1 == "player" ) then
如果发生在玩家身上,应该判断所有技能的可用性
ActionButton_UpdateUsable();
end
elseif ( event == "PLAYER_TARGET_CHANGED" or event == "PLAYER_AURAS_CHANGED" ) then
ActionButton_UpdateUsable();
elseif ( event == "UNIT_AURASTATE" ) then
if ( arg1 == "player" or arg1 == "target" ) then
ActionButton_UpdateUsable();
end
elseif ( event == "UNIT_INVENTORY_CHANGED" ) then
if ( arg1 == "player" ) then
ActionButton_Update();
end
elseif ( event == "ACTIONBAR_UPDATE_STATE" ) then
ActionButton_UpdateState();
elseif ( event == "ACTIONBAR_UPDATE_USABLE" or event == "UPDATE_INVENTORY_ALERTS" or event == "ACTIONBAR_UPDATE_COOLDOWN" ) then
ActionButton_UpdateUsable();
ActionButton_UpdateCooldown();
elseif ( event == "CRAFT_SHOW" or event == "CRAFT_CLOSE" or event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE" ) then
ActionButton_UpdateState();
elseif ( event == "PLAYER_ENTER_COMBAT" ) then
if ( IsAttackAction(ActionButton_GetPagedID(this)) ) then
ActionButton_StartFlash();
end
elseif ( event == "PLAYER_LEAVE_COMBAT" ) then
if ( IsAttackAction(ActionButton_GetPagedID(this)) ) then
ActionButton_StopFlash();
end
elseif ( event == "PLAYER_COMBO_POINTS" ) then
ActionButton_UpdateUsable();
elseif ( event == "START_AUTOREPEAT_SPELL" ) then
if ( IsAutoRepeatAction(ActionButton_GetPagedID(this)) ) then
ActionButton_StartFlash();
end
elseif ( event == "STOP_AUTOREPEAT_SPELL" ) then
if ( ActionButton_IsFlashing() and not IsAttackAction(ActionButton_GetPagedID(this)) ) then
如果该技能在【闪动】,并且不是自动攻击
ActionButton_StopFlash();
end
end
end
function ActionButton_SetTooltip()
if ( GetCVar("UberTooltips") == "1" ) then
Uber,乳房。。。。。
这句应该是判断是否属于一般类型,母类型
UberTooltips详细信息提示
GameTooltip_SetDefaultAnchor(GameTooltip, this);
一般位于屏幕右下角,会根据【动作条】的多少自动改变位置
else
如果这个【栅格】的【信息提示】不属于默认的形式则
if ( this:GetParent() == MultiBarBottomRight or this:GetParent() == MultiBarRight or this:GetParent() == MultiBarLeft ) then
【动作条】MultiBarBottomRight右下,MultiBarRight右方,MultiBarLeft左边下
GameTooltip:SetOwner(this, "ANCHOR_LEFT");
这里解释下SetOwner函数,GameTooltip:SetOwner(owner, anchor);
其中owner是参照物,anchor是对齐方式,取值如下:
ANCHOR_TOPRIGHT 相当于 SetPoint("BOTTOMRIGHT",object,"TOPRIGHT")
ANCHOR_RIGHT 相当于 SetPoint("BOTTOMLEFT",object,"TOPRIGHT")
ANCHOR_BOTTOMRIGHT 相当于 SetPoint("TOPLEFT",object,"BOTTOMRIGHT")
ANCHOR_TOPLEFT 相当于 SetPoint("BOTTOMLEFT",object,"TOPLEFT")
ANCHOR_LEFT 相当于 SetPoint("BOTTOMRIGHT",object,"TOPLEFT")
ANCHOR_BOTTOMLEFT 相当于 SetPoint("TOPRIGHT",object,"BOTTOMLEFT")
else
GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
end
end
if ( GameTooltip:SetAction(ActionButton_GetPagedID(this)) ) then
SetAction,返回值为该【信息提示】是否需要实时更新
this.updateTooltip = TOOLTIP_UPDATE_TIME;
else
this.updateTooltip = nil;
end
end
function ActionButton_OnUpdate(elapsed)
if ( ActionButton_IsFlashing() ) then
this.flashtime = this.flashtime - elapsed;
if ( this.flashtime <= 0 ) then
flashtime初始为0,即第一次flash的时间并不为0.4,而是第一个elapsed决定
local overtime = -this.flashtime;
overtime,该函数的一个中间量,用语变化符号
if ( overtime >= ATTACK_BUTTON_FLASH_TIME ) then
这个if为了下面给flashtime更新是不出现负数考虑
注意,ERROR文本框的文本并不和这里的时间挂钩
overtime = 0;
end
this.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime;
更新flashtime,使得从第二次开始间隔一个ATTACK_BUTTON_FLASH_TIME
local flashTexture = getglobal(this:GetName().."Flash");
if ( flashTexture:IsVisible() ) then
效果的实现即为反复显示这个flash纹理
flashTexture:Hide();
else
flashTexture:Show();
end
end
end
-- Handle range indicator
if ( this.rangeTimer ) then
if ( this.rangeTimer < 0 ) then
local count = getglobal(this:GetName().."HotKey");
if ( IsActionInRange( ActionButton_GetPagedID(this)) == 0 ) then
IsActionInRange,返回指定【动作键】是否在距离之内
返回nil表示该【栅格】无【图标】,或者没有选定目标
返回0表示不在距离之内,返回1表示在距离之内
注意,如果你没有试图释放这个【动作键】在目标身上,它可能总返回1
count:SetVertexColor(1.0, 0.1, 0.1);
else
count:SetVertexColor(0.6, 0.6, 0.6);
end
this.rangeTimer = TOOLTIP_UPDATE_TIME;
else
this.rangeTimer = this.rangeTimer - elapsed;
end
end
if ( not this.updateTooltip ) then
return;
end
this.updateTooltip = this.updateTooltip - elapsed;
if ( this.updateTooltip > 0 ) then
return;
end
if ( GameTooltip:IsOwned(this) ) then
ActionButton_SetTooltip();
else
this.updateTooltip = nil;
end
end
function ActionButton_GetPagedID(button)
if( button == nil ) then
message("nil button passed into ActionButton_GetPagedID(), contact Jeff");
严重错误需要弹出消息框
return 0;
end
if ( button.isBonus and CURRENT_ACTIONBAR_PAGE == 1 ) then
如果是【额外动作条】并且当前【动作条ID】为1
local offset = GetBonusBarOffset();
GetBonusBarOffset,得到【额外动作条】的偏移量
返回1到3,分别对应1到3号战士姿态,或者德鲁依外形,或者是盗贼状态
if ( offset == 0 and BonusActionBarFrame and BonusActionBarFrame.lastBonusBar ) then
应该是判断当意外失去【额外动作条】定位时,定位于最近一次改变的
注意,如果该职业无【额外动作条】时,偏移量也为0
offset = BonusActionBarFrame.lastBonusBar;
end
return (button:GetID() + ((NUM_ACTIONBAR_PAGES + offset - 1) * NUM_ACTIONBAR_BUTTONS));
注意NUM_ACTIONBAR_PAGES + offset用的是加法,所以我们肯定暴雪偷偷藏了24个【额外栅格】
elseif ( button:GetParent():GetName() == "MultiBarBottomLeft" ) then
return (button:GetID() + ((BOTTOMLEFT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS));
elseif ( button:GetParent():GetName() == "MultiBarBottomRight" ) then
return (button:GetID() + ((BOTTOMRIGHT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS));
elseif ( button:GetParent():GetName() == "MultiBarLeft" ) then
return (button:GetID() + ((LEFT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS));
elseif ( button:GetParent():GetName() == "MultiBarRight" ) then
return (button:GetID() + ((RIGHT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS));
else
return (button:GetID() + ((CURRENT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS))
end
end
function ActionButton_UpdateFlash()
local pagedID = ActionButton_GetPagedID(this);
if ( (IsAttackAction(pagedID) and IsCurrentAction(pagedID)) or IsAutoRepeatAction(pagedID) ) then
ActionButton_StartFlash();
else
ActionButton_StopFlash();
end
end
function ActionButton_StartFlash()
this.flashing = 1;
this.flashtime = 0;
ActionButton_UpdateState();
end
function ActionButton_StopFlash()
this.flashing = 0;
getglobal(this:GetName().."Flash"):Hide();
ActionButton_UpdateState();
end
function ActionButton_IsFlashing()
if ( this.flashing == 1 ) then
return 1;
else
return nil;
end
end
---------------------总结一下
常量
TOOLTIP_UPDATE_TIME 【信息提示】更新间隔
CURRENT_ACTIONBAR_PAGE 当前【动作条ID】
NUM_ACTIONBAR_PAGES 总页码
NUM_ACTIONBAR_BUTTONS 一个【动作条】的【栅格】数
ATTACK_BUTTON_FLASH_TIME 【闪动】间隔
BOTTOMLEFT_ACTIONBAR_PAGE 左下【动作条ID】
BOTTOMRIGHT_ACTIONBAR_PAGE 右下【动作条ID】
LEFT_ACTIONBAR_PAGE 右边2【动作条ID】
RIGHT_ACTIONBAR_PAGE 右边1【动作条ID】
事件
ACTIONBAR_PAGE_CHANGED 【动作条】翻页
UPDATE_BONUS_ACTIONBAR 【额外动作条】更新
ACTIONBAR_SHOWGRID 显示【栅格】
ACTIONBAR_HIDEGRID 隐藏【栅格】
ACTIONBAR_SLOT_CHANGED 【栅格】内容变更
ACTIONBAR_UPDATE_STATE 【动作键】更新状态
ACTIONBAR_UPDATE_USABLE 【动作键】更新可用性
ACTIONBAR_UPDATE_COOLDOWN 【动作键】更新【CD】
UPDATE_INVENTORY_ALERTS 装备警告
PLAYER_AURAS_CHANGED 【光环】改变
PLAYER_TARGET_CHANGED 目标改变
UNIT_AURASTATE 单位【光环】改变
UNIT_INVENTORY_CHANGED 单位装备改变
CRAFT_SHOW 工艺窗口显示
CRAFT_CLOSE 工艺窗口隐藏
TRADE_SKILL_SHOW 交易技能窗口显示
TRADE_SKILL_CLOSE 交易技能窗口隐藏
UNIT_HEALTH 单位血量改变(优先级极高)
UNIT_MANA 单位魔法改变
UNIT_RAGE 单位怒气改变
UNIT_FOCUS 单位焦距改变(已废除)
UNIT_ENERGY 单位能量改变
PLAYER_ENTER_COMBAT 开始自动攻击
PLAYER_LEAVE_COMBAT 结束自动攻击
PLAYER_COMBO_POINTS 连击点改变
UPDATE_BINDINGS 快捷键更新
START_AUTOREPEAT_SPELL 开始自动射击
STOP_AUTOREPEAT_SPELL 结束自动射击
函数
IsShiftKeyDown Shift键是否按下
PickupAction 吸附【图标】
PlaceAction 放置【图标】
UseAction 使用【动作键】
GetButtonState 得到【动作键】状态
SetButtonState 设置【动作键】状态
Frame:RegisterForDrag 注册拖拉行为
Frame:RegisterForClicks 注册点击行为
GetBindingKey 得到快捷键
HasAction 【栅格】是否放置了【图标】
Frame:SetVertexColor 顶点色彩修正
IsAutoRepeatAction 是否正在自动射击
IsAttackAction 是否正在自动攻击
IsUsableAction 【动作键】是否可用
IsConsumableAction 是否为消费品
GetActionCooldown 得到【CD】
GetCVar 有待测试
GameTooltip:SetAction 设置【信息提示】
Frame:IsVisible 是否可见
IsActionInRange 是否在距离之内
GetBonusBarOffset 得到【额外动作条】偏移量
累死了。。。。。。明天再贴图片和排版彩色
http://wowbbs.game.mop.com/forumdisplay.php?fid=138
这个帖子我已经贴了图片
posted on 2007-06-25 02:11
七星重剑 阅读(3320)
评论(2) 编辑 收藏 引用 所属分类:
乱七八糟