< 魔兽世界百科 >
您尚未注册/登录
搜索帮助
搜索提示已开启 输入搜索关键词时将自动出现其他玩家的同类搜索词 开启搜索提示 搜索关键词时仍按普通搜索提交框方式输入 什么是智能搜索提示
职业技能 (1199)专业技能 (423)
武器 (2209)防具 (15620)药品 (0)任务道具 (1677)材料 (0)其它 (10399)
商人NPC (981)任务NPC (952)怪物 (7220)其他NPC (10639)
1-10级11-20级21-30级31-40级41-50级50级以上
全部地图 (10091)
WOW动态 (267)WOW学院 (778)职业研究 (27077)副本心得 (1319)天赋交流 (559)任务攻略 (1868)专业技能心得 (740)战场PVP (803)宏与插件交流 (222)
游戏百科 > 魔兽世界 > WOW手册 > 宏与插件交流 > 插件发布与交流 > 百科资料
资源苗 基于游戏百科共建计划 - 了解 | 加入
在魔兽世界中已有97,635项百科条目,如果你有任何可以分享的请
GroupButtons 分析
好东西!投票支持(7)
匿名投票,确认投票给dailytoy
资料版本 1.0,更新时间:2005年10月3日 来源地址
-by sonicling-

本人使用GroupButtons,感觉很强大,因此着重分析了一下他的实现原理。

GroupButtons的作用就是为队伍中每一个人(包括自己)配置一个动作条,该动作条上面的动作只以对应单位为目标,从而使用户只用点击动作条上的图标就可以对指定目标进行施法。

例如德鲁伊给队伍加野性印记,当队伍成员或者自己没有野性印记的时候,一个野性印记的图标就显示在对应的框体旁边,你一点就可以了,无须一个一个选定然后再施法。

GroupButtons很庞大,包含了一大堆的界面及其操作,我重点分析了下面几点:

1、GroupButtons是如何知道自己、队友、目标的状态的呢?
2、诸如中毒、魔法之类的debuff有很多很多,名字各不一样,GroupButtons如何知道对方中毒或者负面魔法的呢?
3、顺便挖掘出来的一些GroupButtons的bug,当然这些bug有可能是因为汉化引起的.

首先看看GroupButtons注册的事件。
在GB_Main.lua文件中有GB_Main_OnLoad()函数,如下:

  CODE: function GB_Main_OnLoad()
        RegisterForSave("GB_Settings");

        this:RegisterEvent("ACTIONBAR_HIDEGRID");
        this:RegisterEvent("BAG_UPDATE");
        this:RegisterEvent("PLAYER_ENTER_COMBAT");
        this:RegisterEvent("PLAYER_ENTERING_WORLD");
        this:RegisterEvent("PLAYER_LEAVE_COMBAT");
        this:RegisterEvent("PLAYER_REGEN_DISABLED");
        this:RegisterEvent("PLAYER_REGEN_ENABLED");
        this:RegisterEvent("PLAYER_TARGET_CHANGED"); --玩家目标改变
        this:RegisterEvent("RAID_ROSTER_UPDATE");
        this:RegisterEvent("SPELLCAST_FAILED");
        this:RegisterEvent("SPELLCAST_INTERRUPTED");
        this:RegisterEvent("SPELLCAST_START");
        this:RegisterEvent("SPELLCAST_STOP");
        this:RegisterEvent("SPELLS_CHANGED");
        this:RegisterEvent("TRAINER_CLOSED"); --玩家关闭技能训练窗口
        this:RegisterEvent("UNIT_AURA"); --单位光环改变
        this:RegisterEvent("UNIT_HEALTH"); --单位生命值改变
        this:RegisterEvent("UNIT_INVENTORY_CHANGED");
        this:RegisterEvent("UNIT_LEVEL"); --单位等级变化
        this:RegisterEvent("UPDATE_BINDINGS");
        this:RegisterEvent("VARIABLES_LOADED");

        SlashCmdList["GB"] = GB_Slash_Handler;
        SLASH_GB1 = "/gb";
        SLASH_GB2 = "/groupbuttons";
end

以上被我注释过的那几行就是GroupButtons核心功能的关键,注释的内容就是对应事件的触发条件,那么接下来就一一看一下GroupButtons是如何处理这些事件的.

首先看看UNIT_HEALTH(身边某一单位的生命值发生改变的时候触发),在GB_Main_OnEvent()函数里面找到如下几行:

  CODE:elseif (event == "UNIT_HEALTH") then
    if (GB_CURRENT_HEAL[1] and arg1 == GB_CURRENT_HEAL[3]) then
        if (GB_Settings[GB_INDEX].cancelHealThreshold) then
            if (not GB_Get_PastThreshold("cancelHealThreshold", GB_CURRENT_HEAL[3])) then
                local text = GB_TEXT.HealCancelledMessage;
                text = string.gsub(text, ’$s’, GB_CURRENT_HEAL[1]);
                text = string.gsub(text, ’$r’, GB_CURRENT_HEAL[2]);
                GB_Feedback(text);
                GB_CURRENT_HEAL = {};
                SpellStopCasting();
            end
        end
    end

对于GB_CURRENT_HEAL,第一次看到这里的时候不理解,GB_CURRENT_HEAL到底是什么?一般这样全大写的名字定义在localization.lua里面的,但是里面只有一行:
GB_CURRENT_HEAL = {};
说明这个是一个运行时期的表。继续找其他的lua文件,看有没有涉及到此变量。终于在GB_Buttons.lua的GB_ActionButton_OnClick函数里面找到了这么几行:

  CODE: if (GB_Settings[GB_INDEX][unitBar.index].Button[button].cancelHeal and castit) then
    GB_CURRENT_HEAL = {spellName, spellRank, target};
end

GB_CURRENT_HEAL[1]就是当前施法的名字,GB_CURRENT_HEAL[2]是魔法等级,GB_CURRENT_HEAL[3]是施法的目标。

那么之前的代码就好理解了:先看看自己有没有施法,再看看自己施法的目标是不是该事件的目标,如果都符合,就看目标的血量是否超过Threshold,如果超过,就停止施法,text是喊话,就不去计较。这里有一个函数值得研究一下:GB_Get_PastThreshold,看名字就知道是检查Threshold的,使用GroupButtons的朋友可能对阈值(Threshold)不理解,不知道这个究竟是当前血量还是减少的血量,是绝对数字还是百分比。看一看这个函数就知道了(在GB_Get.lua中):

  CODE:  function GB_Get_PastThreshold(threshold, target, thresholdnum)
    if ((not thresholdnum) or thresholdnum == "mana") then
        threshold = GB_Settings[GB_INDEX][threshold]; --把threshold从设置中读出来     
    else
        threshold = GB_Settings[GB_INDEX][threshold][thresholdnum];
    end
    --这时的threshold就是你设置的那个字符串,可能在你看来就是一个数字。

    if ((not threshold) or threshold == "") then return true; end

    local damage = UnitHealthMax(target) - UnitHealth(target); --计算伤害量
    --下面是计算百分比
    --注意看,是100-[当前血量]/[最大血量] *100 = 伤害量占总血量的百分比
    local percent = 100 - UnitHealth(target) / UnitHealthMax(target) * 100;
    if (thresholdnum == "mana") then --这个是对应魔法
        damage = UnitManaMax(target) - UnitMana(target);
        percent = 100 - UnitMana(target) / UnitManaMax(target) * 100;
    end
    if (threshold) then
        if (string.find(threshold, "%%")) then--检查阈值字符串中间有没有%,
            _,_,threshold = string.find(threshold, "(%d*)%%");
            threshold = tonumber(threshold);
            --看下面,有%的话就比较百分比
            if (threshold and percent < threshold) then
                return false;
            end
        else
            threshold = tonumber(threshold);
            if (UnitHealthMax(target) == 100 or (not threshold)) then return 0; end
            --没有%就比较绝对值
            if (damage < threshold) then
                return false;
            end
        end
    end
    return true;
end

从上面的代码可以看出来,你填入的阈值可以是绝对数字也可以是百分比,就看你有没有输入%,但不管是整数还是百分数,指的都是伤害量。

UNIT_LEVEL事件没有什么悬念,当附近的同伴升级了以后血和魔法都满了,当然应该把记录更改一下。

接下来看看最为重要的一个事件:UNIT_AURA。

该事件当附近单位身上的buff、debuff变化的时候触发。

  CODE:      elseif (event == "UNIT_AURA") then
        if (arg1 == "target") then
            if (this.targetauras) then
                GB_Update_Auras(arg1);               
            end
        else
            GB_Update_Auras(arg1);
        end

很显然,关键就是GB_Update_Auras,arg1指的是事件的第一个参数,对于UNIT_AURA事件来说第一参数就是单位的编号(诸如"player"、"target"、"party1"、"raid3"之类,而不是名字)。

  CODE: function GB_Update_Auras(unit)
    --如果目标不存在,就不管他了
    if (not UnitName(unit)) then return; end
    --GB_BUFFS和GB_DEBUFFS是用来保存单位光环信息的表,由单位编号来检索
    --既然是光环变化了,而魔兽世界也没有提供到底是什么buff变化了,是消失还是获得,
    --因此在这里清空对应单位的状态
    GB_BUFFS[unit] = {nil};
    GB_DEBUFFS[unit] = {nil};
    --开始重新检索buff和debuff,总共16个buff和8个debuff
    for i = 1, 16 do
        if (UnitBuff(unit, i)) then
            GBTooltip:SetUnitBuff(unit, i);
            if (GBTooltipTextLeft1:IsVisible()) then
                GB_BUFFS[unit][GBTooltipTextLeft1:GetText()] = true;
                if (string.find(GBTooltipTextLeft1:GetText(), "-", 1, true)) then
                    GB_BUFFS[unit][UnitBuff(unit, i)] = true;
                end
            end
        end
    end
    for i = 1, 8 do
        if (UnitDebuff(unit, i)) then
            GBTooltip:SetUnitDebuff(unit, i);
            if (GBTooltipTextLeft1:IsVisible()) then
                GB_DEBUFFS[unit][GBTooltipTextLeft1:GetText()] = true;
            end
            if (GBTooltipTextRight1:IsVisible()) then
                GB_DEBUFFS[unit][GBTooltipTextRight1:GetText()] = true;
            end
        end
    end
end

检索单位的buff和debuff的时候,GroupButtons使用了GBTooltip对象,这个对象在GB_Main.xml中定义,只有一行:(你把鼠标移到某物件上面就会有一个信息窗口探出来,这个窗口就是Tooltip)

  CODE: <GameTooltip name="GBTooltip" frameStrata="TOOLTIP" hidden="true" parent="UIParent" inherits="GameTooltipTemplate"/>

直接继承了GameTooltipTemplate,不是用来显示,而仅仅是用来检索buff的信息。

可以看出GroupButtons检索Buff时只检索GBTooltipTextLeft1(第一行左边的字符串),而检测debuff时,左右两边都检索,这是为什么?

原因很简单,GBTooltip:SetUnitBuff函数就是来生成一个有关Buff的信息,这个信息第一行指出Buff的名字和类型,名字放在左边,类型放在右边(自己把鼠标移到你的buff上面去看看就知道了),类型就是诸如 魔法、中毒、诅咒 或者根本就没有类型。对于Buff,你没有必要去关注Buff的类型,一般的buff都是魔法,还有光环,但是debuff就不一样了,一个接触debuff的技能通常都是解除一类debuff,因此在判断的时候必须要以类型为根据。GroupButtons为了方便,把debuff的名字和类型都加到GB_DEBUFFS中作为索引,那么不管是用这张表的插件是以debuff的名字来检索还是以类型来检索都可以得到正确的答案。

通常,使用GroupButtons的朋友可能遇到一个情况:术士的那个会放火的小鬼(不知道叫什么)的框体旁边,包括什么解毒的,解除诅咒的,解除魔法效果的都出来了,我认为那是GroupButtons的bug,因为你根本无法对这个小鬼施加buff,检索肯定有问题。不过偶也没有想出什么能够解决的办法。不过曾经有一个想法(没试过):每一个单位都有一个生物类型(CreatureType),使用UnitCreatureType(unitID)可以获得对应单位的类型字符串,我想那个术士的小鬼应该是“未指定”类型的,就跟图腾一样,可能他们不被视为带有生命的生物。不过我发现那些软泥怪也是“未指定”类型的。

把GB_Update_Auras函数分析完了,GroupButtons的核心功能也就基本上真相大白了。

PLAYER_TARGET_CHANGED事件就是调用GB_Update_Auras来更改GB_BUFFS["target"]和GB_DEBUFFS["target"]的内容,这个没有悬念。

在这里,最有一个要分析的就是TRAINER_CLOSED事件。

  CODE:      elseif (event == "TRAINER_CLOSED") then
        GB_Spellbook_Initialize();
        if (GB_SPELLS_UPDATED) then
            GB_SPELLS_UPDATED = nil;
        else
            GB_Update_SpellRanks();
        end

GB_Update_SpellRanks()就是自动升级你设置到动作条中的技能,以前每次学了新技能就重新把新的技能拖到GroupButtons里面,一拖,原来的设置就改变成默认的了,比如本来是设置成无此buff时显示,结果变成了总是显示,又要重新设置显示条件。知道分析了GroupButtons的代码才知道,原来GroupButtons已经有自动按照法术书升级技能的功能了。不过到目前为止我还是没有找到如何让他自动更新技能等级。

狡猾的GroupButtons还有一个引人注目的地方,那就是GB_hook.lua里面的GB_Hook_Functions()函数,他把另外的一些插件的函数给掉包了,这样的话,其他插件定义的事件可以为他所用,这一点在设计插件的时候值得借鉴。Sea提供了专门的库函数来进行hook,但是只能hook暴雪给的那些API函数。如何给插件的函数挂钩子呢?GroupButtons给我们以启示。

暂时没有补充内容 您可以第一个补充内容


引用百科资源:多种方式引用本页 | 浏览引用了本页的网站/网页(567)
关闭
百科引用链使您能方便地在其他网页插入本资源的引用链接,让优秀的百科资源通过引用链对更多玩家造成帮助。
越多的玩家通过您的引用链访问百科将为您带来更多的百科威望!

引用本页地址(点击复制到粘贴板) 粘贴到你想引用的网页。
HTML形式的传播:

论坛形式的传播:

关闭
本页有下列读者,字体越大、颜色越深的玩家阅读本页的次数越多。
*如果您的玩家名称未刊载于此,因为只有百科成员才能记录阅读体验。
在魔兽世界中已有97,635项百科条目,如果你有任何可以分享的请

本页由 dailytoy 创建,希望能用你我的开放思维帮助下得到不断完善。
共有 0 条评论 浏览全部评论
匿名发表,您可以马上注册/登录成为百科玩家后用属于自己个性名称发表。

《GroupButtons 分析》的任何感想和见解请发于此。

百科历史纪录
请和我们一起建造全球最大的人工游戏百科
在本目录提交一笔资料 - 我们的计划 - 成为目录编辑
搜游的搜索内容将在 游戏百科共建计划 的基础上不断完善与加强。
当前目录下还没有目录编辑负责管理。
 

想把自己的网站也加上搜索功能?来这里获得免费的魔兽世界搜索条

搜游大全 - 免责声明 - 投放广告 - 商务合作

© 2005 - 2007 搜友游戏百科 SOUYO.com