ouf 头像插件。暗黑风格头像插件。我禁用了团...

[oUF] 1.5版 oUF系插件 通用说明 (FD)
这篇文章的字数越写到后面越刹不住,所以开场白砍了又砍,尽量少说废话. [color=royalblue]开始点击正文传送门:[/color]本主贴起源于自己的读码笔记.内容是站在&插件玩家&的角度,向大家介绍oUF的运作机理 和 制作Layout时的一些惯用法.目的是想让更多同学具备 对ouf系插件自改和排错的能力,尽量减少插件版区的oUF重复性问题. 本人专业和编程只有一毛钱不到的关系,加上大部分内容出于笔记,缺乏权威性,若有错误之处,请大家指出帮我完善,拜谢. [color=royalblue]DONE![/color][quote]一些约定:读者至少有大学编程课的基础(C或java, 相比之下Lua应该是赏心悦目的了)用户: oUF头像插件的制作者. (对于oUF 即为用户)unit: 头像框体所示的角色单位(和游戏宏里的unitid有一点小区分, 团队/小队头像不能通过unitid产生,例如raid12 不在本文的unit概念之内.)Layout: = Layout文件oUF本体: addons\oUF
或者 addons\oUF_xxx\oUF 目录下的内容.组群头像: 包括团队,小队,小队/团队宠物 一类.
但不包括boss和竞技场头像.单位头像: 组群框体中的某单位成员头像.
如团队中 unitid为 raid12 的头像颜色: [color=blue]重要概念[/color], [color=red]重要函数/变量/参数[/color], [color=green]小段代码演示[/color][/quote] [quote][list][b]目录[/b][1] 样式(Style)定义与注册[2] 头像生成(Spawn & SpawnHeader)[3] 样式元素(Elements)[list]&&[3.1] 图标元素&&[3.2] StatusBar类型元素&&[3.3] Tags &&[url=/read.php?tid=4107042&pid=.4] debuff/buff (Auras)[/url](以下章节须传送)[/list]
[url=/read.php?tid=4107042&pid=] 事件与挂载更新(Event , PreUpdate & PostUpdate )[/url][url=/read.php?tid=4107042&pid=]后记[/url][url=/read.php?tid=4107042&pid=]参考(学习)资料和网站[/url][/list][/quote]oUF是一套完整的头像界面驱动器,在功能本质上和pitbull / xperl一样, 这类插件承包了头像界面的所有幕后工作(e.g.框体的建立和初始化,事件注册和响应,显隐判断etc.), 留给玩家的问题都是&看得见&的东西. oUF独特之处于它的定制方式,其他插件用拖拉点选进行设置,
oUF则须要玩家用写lua的方式,ie. Layout文件,告诉ouf本体该如何配置. oUF是以易用性为代价换取自由度的典型.
然而一旦大家掌握了oUF layout的定制方式, 就会发现oUF的这个牺牲是微不足道的.Layout文件本身并不直接产生头像,它只是提供头像的设置模块, 从而被oUF本体调用. Layout文件一般安置在插件主目录下,命名方式无外乎三种: 插件名.lua, core.lua, 或 layout.lua.文件有2个必要成分:[list][*] 定义自己的样式(style),并注册给ouf系统[*] 呼叫ouf 结合自定样式生成(载入)头像.[/list]&&[align=center][b][size=150%]1.
样式(StyleFunc)[/size][/b][/align][color=blue]所谓&样式&,就是一套(头像)界面布局的具体设定.
在layout文件中 样式的存在方式 是一类用户定义的函数. 也可以称之为样式函数.函数体内容全是 对头像框体各功能和显示元素的设置.[/color]按oUF处理机制,样式函数最多可以接收三个参数--- [color=red](self, unit, isheader) : self 接收待处理的框体, unit 接收框体所示的unit,isheader判断框体是否为组群控制柄(暂且无视).[/color]样式函数 必须至少提供第一个参数位(废话,不然连处理哪个框体都不知道..) oUF开动起来后,将会把一个很空洞的头像框体,作为参数值传递给相应的样式函数. 样式函数获得框体参数后,即开始对齐各种设置,ie.血条尺寸,颜色如何变化,法力值以何种格式... 任何ouf插件的所有个性化风格都实现在其样式函数体中.以oUF_simple的layout为例, 其中定义样式的代码片段:[code=lua]
--定义玩家的样式处理函数
--the player style
local function CreatePlayerStyle(self)
--self 参数,经ouf内部传递后,指的是相应的unit头像框体,此处指代玩家头像框体
--style specific stuff
self.width = 250 --设置self框体长度 (显示参数)
self.height = 25 --设置self框体宽度 (显示参数)
self.scale = 0.8 --缩放 (显示参数)
self.mystyle = &player&
--oUF_simple自定义的控制量. 配合libs里的处理
genStyle(self) --与其他头像unit共享的处理
self.Health.frequentUpdates = true
--是否注册血量的高频更新事件 (功能参数)
self.Health.colorClass = true --血量是否根据职业着色 (显示参数)
self.Health.bg.multiplier = 0.3 --背景颜色 于血量的叠加参数 (显示参数)
self.Power.colorPower = true --法力/能量 颜色 (显示参数)
self.Power.bg.multiplier = 0.3 --法力/能量 背景色的叠加参数 (显示参数)
lib.gen_castbar(self)
--产生玩家施法条
lib.gen_portrait(self)
-- 产生玩家头像
lib.createBuffs(self)
--产生玩家buff
lib.createDebuffs(self) --产生玩家debuff
--为其他unit的样式处理函数:
--the target style
local function CreateTargetStyle(self)
--函数体略...
--the tot style
local function CreateToTStyle(self)
--函数体略...
--...&&[/code]oUF_simple本是作为教科书的ouf插件,他为每一个unit单独定义一个样式函数.也有很多插件采用这类简单明了的格式,在函数头部前注释,或直接在函数名(比如function CreateTargetStyle),标明相应函数是哪种头像的样式. 但像 tukui 那种样式处理较复杂的插件,则喜欢把所有unit的处理都集中在一个样式函数里,通常这个函数命名为Share(),顾名思义 就是多个units共享一个样式函数. 这样的话,函数的参数表必须接收oUF传递进来的第二个参数: unit, 以此 在共享样式函数体内区分不同的unit处理片段.以Elvui的Share()为例:[code=lua]&&--为使整个函数结构清晰,略掉了很多细节,完整的一共有1800多行&&local function share(self,unit)&&&&--函数一开始部分,是所有units 都要处理的一些过程.&&&&--e.g.如果玩家要使用点击施法功能,那所有头像必须都要实现,不用区分为哪个unit,如下:&&&&self:RegisterForClicks(&AnyUp&)&&&&self:SetScript('OnEnter', UnitFrame_OnEnter)&&&&self:SetScript('OnLeave', UnitFrame_OnLeave)&&&&-- ......&&&&&&&&--下面根据参数传递进来的unit,区分处理:&&&&&&&&if unit == &player& then &&&&&&--对玩家头像进行处理&&&&end&&&&&&&&if unit == &target& then
&&&&&&--目标头像&&&&end&&&&&&&&if (unit == &targettarget& or unit == &pet& or unit == &pettarget& or unit == &focustarget& or unit == &focus&) then
&&&&&&&&--目标的目标/玩家宠物/宠物目标/焦点/焦点目标&&&&end&&&&if (unit and unit:find(&arena%d&) and C[&arena&].unitframes == true) or (unit and unit:find(&boss%d&) and C[&raidframes&].showboss == true) then
&&&&&&-- 竞技场头像/boss头像&&&&end&&&&&&&&if(self:GetParent():GetName():match&ElvDPSMainTank& or self:GetParent():GetName():match&ElvDPSMainAssist&) then&&&&&&-- 团队主坦或团队辅助 .&&&&end&&&&&&&&&&--接下來又一处共享处理, 对所有非小队头像,添加团队标记图标.
&&&&if unit ~= &party& then&&&&local InvFrame = CreateFrame(&Frame&, nil, self)&&&&InvFrame:SetFrameStrata(&MEDIUM&)&&&&InvFrame:SetFrameLevel(5)&&&&InvFrame:SetAllPoints(self.Health)&&&&&&&&-- symbols, now put the symbol on the frame we created above.&&&&local RaidIcon = InvFrame:CreateTexture(nil, &OVERLAY&)&&&&RaidIcon:SetTexture(&Interface\\AddOns\\ElvUI\\media\\textures\\raidicons.blp&) &&&&RaidIcon:SetHeight(15)&&&&RaidIcon:SetWidth(15)&&&&RaidIcon:SetPoint(&TOP&, 0, 8)&&&&self.RaidIcon = RaidIcon&&
end&&end[/code]
目前为止,ouf与这些样式函数还无任何联系,[color=blue] 必须将它们注册进oUF的样式库,才可以被oUF调用[/color].oUF本体存有一个表数据: oUF.Styles,装载着插件将用到的所有样式函数.使用注册函数oUF:RegisterStyle 即可将样式函数添加到oUF样式库oUF.Styles里去.函数 oUF:RegisterStyle(style,styleFunc) :style为样式名, styleFunc就是定义的函数值 , 执行步骤其实很简单: oUF.Styles[&style&] = styleFunc eg. oUF_Qulight的样式注册段[code=lua]oUF:RegisterStyle(&Player&, CreatePlayerStyle)
注册CreatePlayerStyle ,命名key为&Player&oUF:RegisterStyle(&Target&, CreateTargetStyle)oUF:RegisterStyle(&ToT&, CreateToTStyle)oUF:RegisterStyle(&Focus&, CreateFocusStyle)oUF:RegisterStyle(&FocusTarget&, CreateFocusTargetStyle)oUF:RegisterStyle(&Pet&, CreatePetStyle)oUF:RegisterStyle(&Boss&, CreateBossStyle)oUF:RegisterStyle(&Raid&, CreateRaidStyle)oUF:RegisterStyle(&oUF_MT&, CreateMTStyle)oUF:RegisterStyle(&Party&, CreatePartyStyle)oUF:RegisterStyle(&Arena&, CreateArenaStyle)[/code]像elvui那样只有一个share函数的,此处只须注册一个&oUF:RegisterStyle(&xxx&, Share)&现在对样式已经有了大概的了解, 接着要考虑的就是: oUF是如何结合样式生成头像的.[align=center][b][size=150%]2.
头像生成(Spawn & SpawnHeader)[/size][/b][/align]根据暴雪提供的模板接口,头像分为两类: 一类为单独生成的头像(单体头像),没有组群归属概念,比如玩家,目标,目标的目标等,oUF的生成这类头像的函数为 oUF:Spawn(unit,overrideName); 另一类为组群头像是集体生成的,ie.队伍,团体,团队/队伍宠物,oUF中相应生成函数是 oUF:SpawnHeader(overrideName, template, visibility, ...)layout中,在定义完所有样式函数以后,
就开始为各unit逐一调用这两个函数之一, 来生成oUF式头像.[color=blue]每次呼叫生成函数之前, 必须让oUF明确该使用哪一个样式(函数).[/color]&&[color=red] oUF:SetActiveStyle(stylekey) : stylekey为oUF.Styles中的key. [/color]用于提取样式库中的某样式,使其成为oUF系统当前激活的样式, 在下一次调用SetActiveStyle之前,所有spawn 和 spawnheader生成的头像,都将被 此激活的样式函数处理.再以oUF_simple的layout文件为例, 看 Spawn和SpawnHeader的调用片段:[code=lua]
if cfg.showplayer then
--如果显示 玩家头像
oUF:RegisterStyle(&oUF_SimplePlayer&, CreatePlayerStyle)
--样式在这里注册是比较常见的,假如玩家不想显示该头像,就不用载入多余样式.
oUF:SetActiveStyle(&oUF_SimplePlayer&) -- 激活 key为 &oUF_SimplePlayer& 的样式
oUF:Spawn(&player&, &oUF_Simple_PlayerFrame&)
--生成玩家头像, 框体名为 oUF_Simple_PlayerFrame
--生成目标头像
if cfg.showtarget then
oUF:RegisterStyle(&oUF_SimpleTarget&, CreateTargetStyle)
oUF:SetActiveStyle(&oUF_SimpleTarget&)
-- 现在激活&oUF_SimpleTarget&,刚才的&oUF_SimplePlayer&又退到幕后
oUF:Spawn(&target&, &oUF_Simple_TargetFrame&)
--略去其他单体头像的生成
--生成小队头像:
if cfg.showparty then
oUF:RegisterStyle(&oUF_SimpleParty&, CreatePartyStyle)
oUF:SetActiveStyle(&oUF_SimpleParty&)
local party = oUF:SpawnHeader(&oUF_Party&, nil, &raid,party,solo&, &showParty&, true, &showPlayer&, true, &yOffset&, -50)
party:SetPoint(&TOPLEFT&, 70, -20)
--移动头像位置的控制 一般也在此出现
[/code]生成单体头像的oUF:Spawn(unit,overrideName) 简单直观,没多少要说的. 参数unit即为监视的unitid, overrideName是框架名(可省略).
[b][size=120%][color=red]oUF:SpawnHeader()[/color][/size][/b]就比较复杂了. SpawnHeader生成的对象是一整个头像群(框架). 样式函数只负责其中单个头像的绘制,组群框体中多个头像之间如何组织,显隐控制等, 就是SpawnHeader必须提供的额外工作了. 对SpawnHeader参数表的详细说明如下:&&[color=red]function oUF:SpawnHeader(overrideName, template, visibility, ...)[/color][list]&&&&前三个固定参数:&&&&[color=red]overrideName [/color]框架名&&&&[color=red]template [/color]组群控制模板,一般填nil,让oUF使用默认值&SecureGroupHeaderTemplate& (或在团队宠物框时使用&SecureGroupPetHeaderTemplate&)&&&&[color=red]visibility [/color]实时监视整个框体 显示/隐藏用到的 的条件开关,这里必须填一个判断show/hide表达式,暴雪有机制是0.2秒判断一次这个表达式的结果, 所以你直接填show或hide的话实在没什么意义.
这种表达式经ouf封装后 可有两种格式:&&&&[list]1,[color=blue]给定条件字段: &raid& &group& &solo& &raid40& &raid25& &raid10&,[/color] 每个字段表示一个判断 i.e. &xxx&:玩家当前是否在xxx中.
[color=blue]我们的条件表达式 由这些字段中的任意几个, 用&,&隔开,以&或&关系构成.[/color] e.g. &raid25,group&表示: 若玩家在25人团 或在小队中,则显示框体;无一成立 则不显示.&&&&2. [color=blue]第二种表达式格式为 &custom [condition]hide& 或者 &custom [condition]show&[/color], 头部&custom &必须写的,没什么变数. 后面的字串, 惯用宏的玩家肯定已察觉,其实就是一个条件宏,只不过法术名字变成了show和hide. condition 判断玩家所在团/队情况,如[group:raid]. tukui系插件 常用这类表达式区分25人团/40人团,在它生成25人团时,此处为&custom [@raid26,exists]show& ,当有第26个团队成员存在时(40人团状况),隐藏本团队框体,否则显示.[/list]&&&&&&&&&&&&[color=red]可选参数&...&[/color]&&&&&&&&在这里不可避免的,要提一下暴雪的组群头像生成机制.不像玩家/目标等单体头像,一个头像,一个模板一个创建了事,[color=blue]小队/团队头像是捆绑在一起生成的.暴雪为生成这个群体头像提供了一个集成模板SecureGroupHeaderTemplate(组群控制模板)[/color],其中设有很多属性(Attributes)来控制小队/团队的组织和显示方式,马上有表格说明. 要设定这些属性值 必须用暴雪给定的函数: [color=red]frame:SetAttribute(&Attribute&,&Value&)[/color]&&&&[color=blue]oUF:SpawnHeader 相应的办法是: 把可选参数依次(从整个参数表第四个开始) 成对提取,每一对都传递给SetAttribute的一对参数,并执行一次.[/color] 如相邻的两个参数&xxxx&,&yyyy& 成对后,在oUF内部调用 self:SetAttribute(&xxxx&,&yyyy&).
可以说, SpawnHeader的可选参数表直接的控制了 团队/小队 框体的结构.&&&&可以在可选参数表中出现的属性及相应值类型如下(注意无论属性名还是属性值,都为字串型,必须加引号):[/list][table][tr][td10]Attribute Name[/td][td15]Value Type[/td][td]Description[/td][/tr][tr][td]&showRaid&[/td] [td][BOOLEAN][/td] [td]玩家在raid中是否显示组群框体. 对于&showRaid&
和下面的&showParty& &showSolo&,官方注解(与&wow programming&)说明都不太准确.
showraid和showparty 其实还控制着 整个框体显示的是团队 还是玩家所在小队. 若showRaid为true, 无论showParty和showSolo值如何,当前框架就为团队框架. 若showRaid为false,showParty或showSolo为true,即使玩家在团队中,也不显示团队,只显示玩家所在小队. 由此看出,团队和小队头像其实是一体的,插件有用spawnheader产生团队头像, 也就蕴含了小队实现. [/td][/tr]&&&&[tr][td]&showParty&[/td]
[td][BOOLEAN][/td]
[td]玩家在队伍中是否显示组群框体(另详见&showRaid&)[/td][/tr]&&&&[tr][td]&showSolo&[/td]
[td][BOOLEAN][/td] [td]solo时是否显示框体(另详见&showRaid&)[/td][/tr]&&&&[tr][td]&showPlayer&[/td]
[td][BOOLEAN][/td] [td]队伍框体中是否显示玩家头像[/td][/tr]&&&&[tr][td]&nameList&[/td][td][STRING][/td] [td]只显示列表中的玩家, e.g.&Isaac, Ellie, Lexine,& .如果下面groupfilter有设定,namelist则被忽略.[/td][/tr]&&&&[tr][td]&groupFilter&[/td][td][1-8, STRING][/td] [td]单位头像过滤条件参数. 由8个小队数字+职业(英)大写+团队角色(英)大写 的任意组合,以逗号相隔.e.g.(&1,2,3,4,5,MAGE,HUNTER,WARRIOR,MAINTANK&)[/td][/tr]&&&&[tr][td]&strictFiltering&[/td][td][BOOLEAN][/td] [td]控制groupFIlter的过滤方式,如果true,对某团/队成员,则必须在groupFilter中的队号+职业两个全满足才显示其头像.如果false, 队号,职业,团队角色满足其一即可显示.[/td][/tr]&&[tr][td]&point&[/td][td][STRING][/td] [td]产生新单位头像时的对齐点.系统自动产生相反的&被&对起点.如若设&TOP&,新单位的头像对齐于上一单位头像的&BOTTOM&,若设&LEFT&,则对齐于&RIGHT&. 默认值为&TOP&[/td][/tr]&&&&[tr][td]&xOffset&[/td][td][NUMBER][/td] [td]对齐单位头像时的x偏移[/td][/tr]&&&&[tr][td]&yOffset&[/td][td][NUMBER][/td] [td]对齐单位头像时的y偏移 (默认值和上面x值一样为0)[/td][/tr]&&&&[tr][td]&sortMethod&[/td][td][&INDEX&, &NAME&, &NAMELIST&][/td] [td]头像排列方式[/td][/tr]&&&&[tr][td]&sortDir&[/td][td][&ASC&, &DESC&][/td] [td]降/升序排列 (默认: &ASC&升序)[/td][/tr]&&&&[tr][td]&template&[/td][td][STRING][/td] [td]指定单位头像的使用模板,默认是SecureUnitButtonTemplate(1.5 ouf 还带点击施法模板oUF_ClickCastUnitTemplate)[/td] [/tr]&&&&[tr][td]&templateType&[/td][td][STRING][/td]
[td]模板类型,一般为&Button&[/td][/tr]&&&&[tr][td]&groupBy&[/td][td][nil, &GROUP&, &CLASS&, &ROLE&][/td]
[td]单位成组方式. &GROUP&就是一般的每小队为一组.&CLASS&按职业成组.&ROLE&按团队角色成组(默认: nil,不成组)[/td][/tr]&&&&[tr][td]&groupingOrder&[/td][td][STRING][/td]
[td]分组排列方式 (e.g. &1,2,3,4,5,6,7,8&)[/td][/tr]&&&&[tr][td]&maxColumns&[/td][td][NUMBER][/td]
[td]显示最大列(或行,取决于&point&属性)数, 默认是1列;[/td][/tr]&&&&[tr][td]&unitsPerColumn&[/td][td][NUMBER or nil][/td]
[td]每列(行)最多单位数, 默认是nil,表示无数个.[/td][/tr]&&&&[tr][td]&startingIndex&[/td][td][NUMBER][/td]
[td] 头像列的起始序号(和unitid的id是两码事,默认值为1,一般不须改动) [/td][/tr]&&&&[tr][td]&columnSpacing&[/td][td][NUMBER][/td]
[td]列(行)间距 (Default: 0)[/td][/tr]&&&&[tr][td]&columnAnchorPoint&[/td][td][STRING][/td]
[td]列(行)的对齐点,和&point&的设置和对齐方式一样.[/td][/tr]&&&&[tr][td]oUF-initialConfigFunction[/td][td][SNIPPET][/td][td] (国服玩家不用理会此项)这个属性是暴雪内置属性&initialConfigFunction&的oUF版,原版和oUF版执行原理都一样, 属性值是一个代码片段(须引号!),任何时候,组群框体内产生新的单元头像时,将对单元头像执行这个代码片段.
1.5版oUF将原版属性留给自己本体处理([color=red]包括样式调用[/color]),处理中有一步是检查oUF-initialConfigFunction是否存在,如存在,调用之.这样用户只设置oUF-initialConfigFunction,但效果和原版差不多. 实际看来这个属性的使用很简单,就是设定单元头像高宽. e.g. oUF_Drk\core.lua L449 &&&&&oUF-initialConfigFunction&, ([[&&&&self:SetWidth(%d)&&&&self:SetHeight(%d)&&&&]]):format(72, 28))[/td][/tr][/table]此外 可以在可选参数表中添加自定义的属性,就像oUF添加自己的&oUF-inittialConfigFunction&属性一样.下面看一个团队生成的例子: elvui\ElvUI_Dps_layout\raid\raid25.lua L239
25人团框体生成过程:&&&&[code=lua]&&&&--SpawnHeader的调用看上去像一段代码, 从它参数表第四个起,每两个参数为一行,以便加强&成对处理&的读码印象.&&&&raid = self:SpawnHeader(&ElvuiDPSR6R25&, nil, &custom [@raid6,noexists][@raid26,exists]show&,
--注意第三个显隐控制参数,如果raid6不存在(小队情况) 或raid26存在(40人团情况),则隐藏框体;否则(25人团)显示.&&&&&&'oUF-initialConfigFunction', [[&&&&&&&&local header = self:GetParent()&&&&&&&&self:SetWidth(header:GetAttribute('initial-width'))&&&&&&&&self:SetHeight(header:GetAttribute('initial-height'))&&&&&&]],
-- 一样是设置高宽,不过为兼容1.4 oUF作此安排(见下面两项,其实也没兼容到哪里去..)&&&&&&'initial-width', raidframe_width,
--和下面一项为1.4 oUF版 的oUF-属性,用来控制单元高宽&&&&&&'initial-height', raidframe_height,&&&&&&&&&&&&&showRaid&, true,
-- 如果在团队中,则显示为团队.&&&&&&&showParty&, true,
-- 不在团队中, 也显示为小队.(但注意! 第三个固定参数设置 已将 本项无视)&&&&&&&showSolo&, false,
-- solo时 不显示.&&&&&&&point&, &BOTTOM&,
-- 新单元底部对齐于上一单元上部. (向上扩展)&&&&&&&showPlayer&, C[&raidframes&].showplayerinparty,
--在队伍中显示玩家.&&&&&&&groupFilter&, &1,2,3,4,5&,
-- 队伍过滤,只显示12345队&&&&&&&groupingOrder&, &1,2,3,4,5&,
-- 分组顺序 1,2,3,4,5组顺序.&&&&&&&groupBy&, &GROUP&,&&
-- 分组依据按小队.&&&&&&&yOffset&, E.Scale(6)
--对齐单元时,向上偏移6p.&&&&)&&&&&&[/code]Layout整个结构介绍到此结束. 下半部介绍的是样式内部的细节.[align=center][size=150%][b]3.
样式元素(Elements)[/b][/size][/align][color=firebrick](本章主题会涉及大量暴雪原生API, wowwiki和&wow programming&主页 对此已经阐述得相当详尽.本文重在介绍oUF相关的知识,对原生API也没必要过多重复.
那么, 在文中出现各类oUF功能元素的地方, 就只在括号里指明它们的类型:&TYPE&.读者若感兴趣, 可在谷歌中, 按这个格式搜索: &TYPE &, 即可查到此类型支持的所有暴雪API. e.g. google &Texture &. )[/color]回到样式函数体内部, 细看之下,不论是调用自建lib,还是产生新的局部变量,
每一步的目的 要么就是 给self.xxx.xxx赋值,
要么就是用self.xxx:func()调整self.xxx.
所有处理都针对于 框体self下的某些域.[color=blue] oUF把 一个头像框体变量self下 可被样式函数处理的域对象 定义为&element&(元素). [/color] 如血条 self.Health, 能量条 self.Power, 3D头像self.Potraits. 设置一个头像的外观,具体而言 就是设置这些element的外观.elements属于oUF可扩展的成分, 用户可以添加自己的element. 有很多oUF plug-in就是如此,如oUF_Experience.载入即可在样式函数里设置self.Experience(经验条).和头像框体不同,element的实体 须要用户来操作生成,而非oUF的职责.
oUF本体内, 在实现 self.xxx 的底层功能之前, 都要先判断 self.xxx 是否真的存在,不存在就完全忽略.
oUF的elements目录里有一altpowerbar.lua, 即加载oUF版的boss战第二能量条(丘加利的糖葫芦,瞎子龙的音波值),
但是假如在样式函数中,没有将任何实体赋值给self.AltPowerBar的话,
在oUF将要为头像载入altPowerBar模块的时候,就会获知self.AltPowerBar为nil, 则立即中止载入模块返回,结果就是第二能量条仍保持暴雪默认的那个, 无任何变化.因此用户若要处理某元素, 必须赋予它指代的实体. 当然这也给了用户选择元素模块的自由,像第二能量条很少有oUF插件去动它.([color=blue]玩家如果不想使用插件的某个样式元素,可以将其样式元素的对象置空. 比如习惯quartz的同学,可能不想显示oUF头像的施法条,那最简单的操作,就是在相应头像的样式函数里,找到self.Castbar的赋值语句, 将其置空:
self.Castbar = nil.[/color], 注意,一些元素可以在config.lua里关闭掉.)设置元素大小尺寸和位置的函数 为所有样式元素所共有(包括下级子元素),使用最频繁,有必要先提一下:[list][color=red]self.Element:SetPoint(point,relFrame,relPoint,x,y) [/color]
设置Element的依附点(作用于位置 或 区域覆盖)[color=red]self.Element:SetAllPoint(frame)[/color]
使Element整个区域与frame完全重合[color=red]self.Element:SetSize(w,h) [/color]
设置Element高宽尺寸 w x h[color=red]self.Element:SetWidth(w) [/color]
长度[color=red]self.Element:SetHeight(h)[/color]
高度[color=red]self.Element:SetFrameLevel(n)[/color]
与其他界面重合时, 本Element的显示优先级,数字越高,层级越高.说明:[color=red]frame:SetPoint(point,relFrame,relPoint,x,y)[/color]
的功能很直观.把frame想象成一块收缩拉升都很自如的面板,
SetPoint的作用就是 用大头钉把这个面板上某点(point) 和 另一面板(relFrame)的某点(relPoint) 钉一起.在钉之前,允许point相对relPoint产生一段偏移(x,y). point和relPoint 只能在 各自面板上 固定的8个点中取(除4个角点外,还有正上方,正下方,正左和正右.). self.Element:SetPoint 使用一次的话, 只为固定位置.
若使用多次,还起到调整高宽的作用. 比如self.Health:SetPoint(&LEFT&,self,&LEFT&); self.Health:SetPoint(&RIGHT,&self,&RIGHT&)
: 即将血条和头像框,左侧与左侧对齐, 右侧与右侧对齐,以此调整血条的长度.另要强调的是,&大头钉&的作用是实时的, 像上一例中,头像的长度在后面发生变化时,血条长也会跟着变化. 只有对血条调用self.Health:ClearAllPoints 才会解除这种依附关系.[/list]样式元素各自常见的一些惯用处理如下:[b][size=120%]3.1 图标元素(类型Texture)[/size][/b]提示战斗的小刀叉,标明装备拾取者的小布袋..这类小图标是样式处理中最简单的元素. 为这些元素赋值的时候 创建一个空材质即可,不用考虑冗长的材质文件目录.比如[color=bat = self:CreateTexture(nil,&OVERLAY&) [/color]在这些图标元素内部模块中, 会自动绘制暴雪默认的图标材质.用户只须考虑它们大小和位置. 如 bat:SetSize(12,12)
bat:SetPoint(&TOPLEFT&,0,5)常用的图标元素包括:[color=red]self.Assistant[/color] 团队辅助,
[color=bat[/color] 战斗指示, [color=red]self.Happiness[/color] 宠物满意状态指示, [color=red]self.Leader[/color] 队长图标, [color=red]self.Masterlooter[/color] 装备拾取者, [color=red]self.PvP[/color] pvp状态, [color=red]self.RaidIcon[/color] 团队标记, [color=red]self.Resting[/color] 休息状态, [color=red]self.QuestIcon[/color] 任务怪图标, [color=red]self.LFDRole 随机本角色, [color=red]self.ReadyCheck[/color] 准备就绪状态.[b][size=120%]3.2 StatusBar(状态条)类型元素(self.Power, self.Health, self.Castbar)[/size][/b]法力/能量条([color=red]self.Power[/color]),生命条([color=red]self.Health[/color]), 施法条([color=red]self.Castbar[/color]) 的实体都是StatusBar类型的frame, 先演示一下他们在操作上的一些共性. (展开分别介绍之前,先以'xBar'来代表'Health', 'Power', 'Castbar'之一.)在处理量上,这三个元素向来都是样式函数中的成分大户, 如果一上来就&self.xBar = CreateFrame...&, 那么后面好几行都得戴着'self.'这顶帽子,代码看起来太冗余.
以好的代码习惯,都会在开头先将实体定义给一个局部变量, ie. &xbar = createframe...&,用这个'xbar'来完成所有设置后, 再将它赋值给样式元素
self.xBar = xbar. 这也带出一个用ctrl+F捕捉代码的tip, 你搜索样式元素时,尽量带上&self.&, 会大大增加命中率,比如要找&castbar&,就搜&self.castbar&.StatusBar是Frame类别之一,可用CreateFrame函数创建:[color=green][i]local xbar = CreateFrame(&StatusBar&,self:GetName()..&xBar&,self)[/i][/color]---- 第二个参数中, self:GetName()取得头像框体名字,然后连接上'xBar' 作为xbar的frame名.紧接着,个性化最重要的成分--状态条材质: [i][color=green]xbar:SetStatusBarTexture(textureFile or textureOjbect,layer)[/color][/i]---- 第一参数中,oUF插件倾向于 直接填文件路径名:从&interface&一路到材质文件名(材质文件,tga或blp类型,一般都放在media\下),不包括文件扩展名.如 &Interface\\AddOns\\oUF_xxx\\media\\barTexture&. oUF插件经常把此类文件路径名保存在config.lua中.---- layer为材质在本frame(此处即xbar)内的显示层数,层数越高,显示优先级越高.默认'ARTWORK'.以下会将会看到这个参数的影响.状态条还支持调整材质颜色:[color=green][i]xbar:SetStatusBarColor(r,g,b,alpha) [/i][/color]---- alpha为透明度,可缺省.
给定状态条材质后, SetStatusBarColor的作用就不再是染纯色了, 而是将参数里的rgb值分别与材质的rgb值相乘,得出最终显示的rgb. 也就是ps里的&正片叠底&的处理原理.完整的oUF状态条有两层材质重合而成,除了 xbar本身为一层,还需一静态的背景材质,衬在底部以加强状态减少量 的视觉印象.在oUF元素结构中,这一背景层作为statusbar元素下的子元素而存在,名为'bg' (background),产生例子如下:[color=green][i]local bg = xbar:CreateTexture(nil,&BACKGROUND&)
bg:SetTexture( textureFile )bg:SetVertexColor(r,g,b,a)bg:SetAllPoints(xbar)xbar.bg = bg[/i][/color]下面分别介绍三种主要StatusBar 的oUF惯用设定.[b][color=red][size=120%]self.Health [/size][/color][/b]血条,也包括能量条的设定,主要是控制血条颜色变化,由一堆布尔值开关决定.
[list][color=red]self.Health.colorTapping[/color]
是否反映&他人首击& (怪被别人抢了)[color=red]self.Health.colorDisconnected[/color]
是否反映离线状态[color=red]self.Health.colorHappiness[/color]
是否反映 (宠物)满意度[color=red]self.Health.colorClass[/color]
是否显示为职业颜色[color=red]self.Health.colorReaction[/color] 是否反映 目标于玩家的声望态度(敌对,友好...)[color=red]self.Health.colorSmooth[/color] 颜色是否根据血量变化产生渐变 (很常用的设定,血满为绿色,血低变红.颜色如何设置见下面)[color=red]self.Health.colorHealth[/color] 是否自定义的血条颜色
(套用的固定色定义于self.colors.health )[/list]说明点:1、 参数值默认都是nil, 如果你不想打开开关,没必要声明 self.Health.colorClass = false . 纯属多余2、 这个开关列表是按判断优先顺序先后排列的, 比如当 self.Health.colorClass 为true,且oUF判定头像角色有可选职业色时, 就直接以相应职业色染色 , 而忽略下面的self.Health.colorSmooth 和self.Health.colorHealth.3、 产生的颜色并不会以纯色覆盖材质文件. 仍为正片叠底模式.4、 [color=blue]状态条的颜色变化 同时也影响着 背景材质的颜色[/color],
可通过[color=red]self.Health.bg.multiplier[/color] (0~1的小数)来控制,背景颜色(rgb)就是状态条颜色r g b分别与这个参数的乘积.
如果感觉前景相对背景颜色不够分明, 可降低multiplier值,这个值越低,背景材质的色调越暗. 5、
[color=blue]用户可以自定义各类反应颜色[/color]:
所有样式颜色 取自于 样式函数中 &self.colors& 指向的表. 但很少有插件会在函数中直接定义这张表,
self.colors如果不是指向插件某处, 就是直接套用oUF目录下colors.lua里的oUF.colors. ctrl+F搜索到之后,你有两个选择,
一,在&self.colors =& 等号后的表实体中修改, 比如tukui中 &self.colors = T.oUF_colors&
T.oUF_colors 存在于&...\Tukui\modules\unitframes\templates\colors.lua&
二,参考colors表的结构,直接替换self.colors下的域值. 如执行: [color=green]self.colors.tapped = {.5,.5,.5}[/color] .
oUF默认的colors表(oUF\colors.lua)结构如下(有些插件经过扩展可能有些不同,不过读者理解后,见key名自然明白)[code=lua]-- 所有颜色值都是 &{r,g,b}& 格式,
r/g/b 都为0~1的小数, 也可写为 v/255,
v:0~255local colors = {&&happiness = {
--宠物满意度&&&&[1] = {1, 0, 0}, -- need.... | unhappy&&&&[2] = {1, 1, 0}, -- new..... | content&&&&[3] = {0, 1, 0}, -- colors.. | happy&&},&&smooth = {
--colorSmooth为true时 调用的渐变颜色 (可设置多个颜色点, 将被平均分配在渐变距上.比如定义三种颜色时,在状态量33% 66% 100%依次分配颜色点 )&&&&1, 0, 0,&&&&1, 1, 0,&&&&0, 1, 0&&},&&disconnected = {.6, .6, .6},
--离线&&tapped = {.6,.6,.6},
--&他人首击& 一般显灰&&class = {},
--职业色, 和下面的声望态度, 在oUF载入时,会自动被赋予暴雪内部的相应色.&&reaction = {},
--声望态度}[/code]其中,渐变色也可以直接定义在样式元素的子元素中, 表名为[color=red]smoothGradient[/color],
如[color=red]self.Health.smoothGradient[/color][color=green]= {&&1, 0, 0,&&1, 1, 0,&&0, 1, 0}[/color]
, smoothGradient 会覆盖self.colors表中smooth定义,
让各头像血条产生有自己的渐变色.[b][color=red][size=120%]self.Power[/size][/color] [/b] 将上面 self.Health 颜色各项中的Health改成Power后 ,所有设置 一样作用于self.Power. 但有一项必须不同: [color=red]self.Power.colorPower[/color] 是否套用能量色, 和self.Health.colorHealth不同,
首先,这一项在self.Power所有颜色定义中的优先判断级比较高,除去&他人先击&&断线&和&满意度&下来,第一个&常驻色&就是能量色.
然后,不想health版只套用一自定的固定色, colorPower置true后, oUF会根据能量类型,给Power条上色. 这点不用用户操心, 类型颜色都来自于暴雪内部定义.[b][color=red][size=120%]self.Castbar[/size][/color] [/b]不同于血条和法力条, 施法条的颜色一般不须用户加以控制, 主要设置集中在各部件的位置组织上. castbar除了状态条主体外,还蕴含以下成分元素:[list][color=red]castbar.Text[/color]
(FontString)
施法条上的法术名[color=red]castbar.Time[/color]
(FontString)
读条持续时间[color=red]castbar.Icon[/color]
(Texture) 法术图标[color=red]castbar.Spark[/color]
(Texture) 施法条头部的闪光[color=red]castbar.SafeZone[/color]
(Texture) 延迟区域[color=red]castbar.Shield[/color] (Frame / Texture)
反映法术不可打断.(暴雪默认是个盾图标)[/list]说明:1. castbar.Text castbar.Time都为Fontstring类型, 和Texture(材质) 同属于暴雪 层对象(也就这两种.) [quote][b]层级对象[/b]: 包括两类界面元素, FontString(显示字符)和Texture(材质).这类对象与用CreateFrame函数建立的框架 最大不同之处在于,它们只能被看见, 不能被摸(点)到, 纯粹是暴雪绘制模块的产物,一般不直接接受鼠标事件及其他用户输入. 另外有一点不同在于它们的必须从属于其他frame之下, 因此,生成函数也属于frame的接口, i.e.
frame:CreateFontString(name,layer)
frame:CreateTexture(name,layer).[/quote]2. castbar.Icon 是不加任何修饰的法术图标, 独立存在的话不太好看 所以常会辅以边框背景, 有些插件就会多创建一个frame.那么移动castbar.Icon的时候 ,要确保与背景frame依附.3. castbar.Spark,castbar.Shield 和图表样式元素一样,无需提供具体材质,oUF内部自动产生. 但若用户设定了自定材质,则oUF自匿之.[b][size=120%]3.3 标签字段(Tags)[/size][/b]界面上常驻的字段信息,基本上都属于内置类型FontString,像上一节的施法条, 用了两个fontstring:法术名和施法时间,系统通过事件获知法术信息后,即用api SetText()函数 设定法术名和时间的显示内容. 但是, 对于个性化要求高,设定频繁的字段元素,
每次都要完成一次从事件绑定到格式化的流程,显得过于繁琐,而且对玩家而言也不太友好.如有的玩家更喜欢看到准确的生命值,而非百分比,这都是很容易遇到的问题.为此, oUF将 FontString对象 的内容设定和事件过程加以封装,产生了标签模块.
玩家不用再深入事件监视过程, 只须直接改变 绑定于fontstring对象中的标签组合 ,相对来说直观了许多.[color=blue][b]什么是标签[/b][/color]1、标签的格式是 由中括号括起的一字段,形如 [xxxx]
正则表达式为
%[..-%] .2、每一个有效的oUF标签, 在任何时刻,都对应着一个 普通字段型的标签值. 比如[name] , 任何时候 都为头像所示单位的名字,
[curhp] (扩展标签)为当前时刻 当前头像的血量值3、在oUF为FontString产生显示内容时, 一个或多个标签组成的集作为处理的输入, 过程中,每个标签分别被替换为 当前的 标签值. 但非标签成分(中括号之外的内容),标签所在的位置格式都原封不动. 比如 '[name]'s gender is [sex].' 被处理后, 变为 'Desmond's gender is Male.'
或 'Morrigan's gender is Female.' ...
若无性别信息, 则为 'Gordok's gender is .' 标签的应用很简单, 只要把安排好的标签组合,绑定于字段对象(FontString)就可以了,下面演示一段调用情况,顺带几个细节.假设我们要为头像添加名字信息,
显示样式为 &名字 等级&, 并且为名字按职业染色:首先 我们要创建 承载字段信息的实体, 即一个FontString类型的对象. 在上一节中有提到,这是一个层级元素,隶属于其他框架,为方便定位,就选择血条为其父框架:[color=green]local name = health:CreateFontString(nil,&OVERLAY&)
--以下是FontString的常规设置name:SetFont(fontfile,12,&OUTLINE&)name:SetJustifyH(&LEFT&)name:SetPoint(&LEFT&,5,0)[/color][color=red][b]然后用 unitframe:Tag(fontString,tagstring) 绑定标签于FontString对象上:[/b][/color][color=green]self:Tag(name,'[raidcolor][name] |r[level]')self.Name = name[/color]说明:1、Tag() 参数表简单, 第一个为被绑定的fontString 对象,第二参数为绑定的标签组合。2、[color=blue]Tag()被安置于oUF头像框体之下,作为一个子函数. 因此在样式函数内,调用此函数须冠以&self:&. [/color] 3、把第二个参数里的内容叫成 标签组合 其实也不太准确,想不出更好的名字,暂且如此吧.但须知这个参数,也包含了最终字段内容的格式信息. 类似于string.format的第一个参数(formatstring). 4、oUF运作时 凡是须要显示或更新 name内容时,
就处理一次 '[raidcolor][name]
|r[level]' ,完整的处理简单演示如下(实际过程复杂多,这里为便于理解):
如头像当前所示的是一个17级萨满名叫Enclave. 过程中, 遇到的第一个标签[raidcolor],换成萨满的职业颜色'|cff0070DE'; 紧接着[name]替换成'Enclave', 然后是一个空格和一个颜色重置符'
|r',非标签内容保持不变,最后是[level],替换成'17', 处理结果:'|cff0070DEEnclave
|r17',将其设定为对象name的内容,显示(更新)于血条左部.oUF内置支持的 标签表:[code=lua]--------------------------
tip: use Ctrl+F -----------------------------------------------------------------------------------------------------标签&&&&&&&&&&
解释&&&&&&&&&&&&&&&&&&
标签值例[creature]&&&&&&&&生物类型&&&&&&&&&&&&&&&&
&野兽&,&恶魔&&&[dead]&&&&&&&&&&死亡情况&&&&&&&&&&&&&&&&
&Dead&,&Ghost&[difficulty]&&&&&&反映等级差(颜色)[leader]&&&&&&&&是否队长&&&&&&&&&&&&&&
&&&L&[leaderlong]&&&&&&同上&&&&&&&&&&&&&&&&
&&&Leader&[level]&&&&&&&&&&等级&&&&&&&&&&&&&&&&&&
&85& &??&[missinghp]&&&&&&&&生命减少值&&[missingpp]&&&&&&&&能量减少值&&&&[name]&&&&&&&&&&名字&&&&[offline]&&&&&&&&断线情况&&&&&&&&&&&&&&
&&&Offline&[perhp]&&&&&&&&&&百分比生命值[perpp]&&&&&&&&&&百分比魔法值[plus]&&&&&&&&&&精英标识&&&&&&&&&&&&&&&&&&&+&[pvp]&&&&&&&&&&PvP标识&&&&&&&&&&&&&&&&&&&&&pvp&[raidcolor]&&&&&&&&职业颜色码(Hex)&&&&&&&&&&&&&&&|cffABD473&[rare]&&&&&&&&&&稀有怪标识&&&&&&&&&&&&&&&&&&&Rare&[resting]&&&&&&&&休息标识&&&&&&&&&&&&&&&&&&&zzz&[sex]&&&&&&&&&&角色性别&&&&&&&&&&&&&&&&&&&Male& &Female&[smartclass]&&&&&&若为玩家:职业;若npc/怪物:生物类型[classification]&&&&怪物分级&&&&&&&&&&&&&&&Rare& &Rare Elite& &Elite& &Boss&&&[shortclassification]&&怪物分解(简)&&&&&&&&&&&&&&&&&R& &R+& &+& &B&[group]&&&&&&&&&&所在队号(raid中)[deficit:name&]&&&&&&若伤血显示为伤血值;若满血显示为名字[happiness]&&&&&&&&宠物满意度(文字)&&&&&&&&&&&&&&&:&&&&&:|&&&&:D&[pereclipse]&&&&&&平衡德日月蚀能量值(0~100)[curhp]&&&&&&&&&&当前生命值[curpp]&&&&&&&&&&当前能量(法力)值[maxhp]&&&&&&&&&&最大生命值[maxpp]&&&&&&&&&&最大能量(法力)值[class]&&&&&&&&&&职业[faction]&&&&&&&&阵营&&&&&&&&&&&&&&&&&&&Alliance& &Horde&[race]&&&&&&&&&&种族[/code][color=blue][b]自定标签[/b][/color][color=silver]约定,在例子和解释中, fs表示被绑定标签组合的某FontString对象[/color]oUF本身支持的标签其实并不算多,尤其在颜色方面,很多标签需要用户自己定义.oUF向用户公开了 可支持的标签库 和与之相关的两个事件管理表. 通过这三个表,用户可以添加自己的标签. 一般, 插件主目录下tags.lua 就是集中添加标签的执行文件.[color=red]oUF.Tags oUF.TagEvents oUF.UnitlessTagEvents [/color]介绍这三者之前,须了解一下标签的重解释机制.
在为字段对象fs绑定标签组合后, 有三种情况会使 oUF(重新)解释标签.1、fs所在的头像框体呼叫 全体元素更新函数时(self:UpdateAllElements). 比如目标头像 在玩家切换目标时, 会呼叫一次.头像的监视对象变了,当然要更新所有样式元素,包括所有字段信息,标签须重新解释一遍.这应该不难理解,2、fs.frequentUpdates 如果有被设定, 比如 = 0.5,
则oUF每隔0.5秒将 fs绑定的标签组合重新解释一遍.3、[color=blue]每个标签都可以设定自己对应的监视事件,事件触发时,标签就须重新解释一次. [/color] 这些[color=red]标签事件都注册在oUF.TagEvents表[/color]中, 以标签名为key. 如oUF.TagEvents[&curpp&]='UNIT_POWER' , 当 能量值改变事件 产生时, [curpp]需要重新解释.
但是标签本身不是实体, 响应事件的必须是作为标签载体的FontString对象. oUF是这样解决的:
某标签组合绑定于FontString对象 fs的同时, 将标签组合中的所有标签的监视事件 也一并绑定于 fs.
然后这个事件集中一旦有触发,
会先判断事件信息的unit参数 是不是 fs描述的unit, 如果是 就将整个标签组合重新解释一次.
但这里又有一个新问题, 假如事件信息不传递unit参数,或者有些标签描述的unit 本来就与事件的unit参数不符,这种情况该如何判定fs标签要不要重新解释? 比如在目标身上显示连击点的标签[cpoints],对应事件为UNIT_COMBO_POINTS,[cpoints]肯定被安置在目标头像的fs里,描述对象是target,
但是 UNIT_COMBO_POINTS的unit参数是发出攻击的玩家.
解决办法是,oUF要求 像这样的事件 必须同时注册于[color=red]oUF.UnitlessTagEvents[/color] (如 [color=green]oUF.UnitlessTagEvents['UNIT_COMBO_POINTS'] = true,[/color]),顾名思义, 如果事件出现在这张表中,那么该事件触发时, 在判断过程中无论事件unit信息是谁,都要重新解释标签.了解标签事件驱动后 ,剩下的问题只有如何解释本身了,即定义标签值. [color=red]oUF将当前所有合法标签的定义函数都保存在表oUF.Tags中.[/color] 解释标签的过程, 就是查找[color=red]oUF.Tags[/color]这张表, 在keys中找到标签名,执行后面的函数体,获得标签值.以tukui tags.lua中 [Tukui:getnamecolor]标签的定义,看下自定标签的完整过程:[code=lua]--------------[Tukui:getnamecolor] 标签值是 为头像框体的角色名字产生hex颜色值.oUF.TagEvents['Tukui:getnamecolor'] = 'UNIT_HAPPINESS'
--注册标签对应的重绘事件: 满意度变化事件-- 以下处理中, 只有宠物满意度是随事件变化的,其他判定, 在头像所示单位无变换的情况下,不会有改变(即:可随UpdateAllElements()一起处理),因此只须注册一个事件.--一般标签值定义函数只用给一个参数unit(当前头像框体所示unit), 第二个可选参数realunit比较罕见, ----头像所示单位在道具载具上,头像会改成载具,这时候self.realunit指向载具上的玩家单位.(暂时没区分出来,何种情况换用realunit?)oUF.Tags['Tukui:getnamecolor'] = function(unit)
&&local reaction = UnitReaction(unit, 'player')
&&if (unit == 'pet' and GetPetHappiness()) then
--若unit为宠物,根据宠物满意度 解释出颜色值&&&&local c = T.oUF_colors.happiness[GetPetHappiness()]&&&&return string.format('|cff%02x%02x%02x', c[1] * 255, c[2] * 255, c[3] * 255)&&elseif (UnitIsPlayer(unit)) then
--若unit为玩家,解释为职业颜色值&&&&return _TAGS['raidcolor'](unit)&&elseif (reaction) then
--根据声望态度值 &&&&local c = T.oUF_colors.reaction[reaction]&&&&return string.format('|cff%02x%02x%02x', c[1] * 255, c[2] * 255, c[3] * 255)&&else
-- 以上都不是, 即解释为 某固定颜色值.&&&&r, g, b = .84,.75,.65&&&&return string.format('|cff%02x%02x%02x', r * 255, g * 255, b * 255)&&endend[/code]
[align=center][size=200%][url=/read.php?tid=4107042&pid=]---------------终于放倒一贴,以下内容传送门------------------[/url][/size][/align]
这。。。居然没人支持?顶一个
好贴~ mark一下,游戏完仔细学习一下
正愁不会隐藏Tukui的小队和团队框架呢,看到上面的 &ShowRaid&
&ShowParty&豁然开朗~
虽然不咋太懂,不过果断支持啊!
不懂的人还是不懂,懂的人不屑一顾. 前半段基本是肯定的,后半段不一定吧。我支持你。
我很少动用帖子管理权限,这是我加精的唯一一个帖子,够支持了吧?继续加油。
这个。。技术贴。搬个小板凳.....
标记一下继续学习中关键是要实战操作~
[quote][pid=][b]Post by Alice01 ( 20:10):[/b][/pid]不懂的人还是不懂,懂的人不屑一顾. 前半段基本是肯定的,后半段不一定吧。我支持你。
我很少动用帖子管理权限,这是我加精的唯一一个帖子,够支持了吧?继续加油。[/quote]谢谢A大,我会继续努力的前半部原理性问题确实有点多,有些东西自己动下手就领悟了,光看理论不靠谱,感觉是有点徒劳. 我还是尽量提炼一些方便查阅的参考性信息吧
没什么实用性...
我觉得玩OUF经常是一个增量式开发的模式。
太激动了!终于有oUF比较详尽的说明了!mark!
话说楼主不要丧气啊。上篇Tukui并非没有实用性,只是国内本就用tukui的人少,有特别的自定义需求的更少了。oUF的关注者还是非常多的
mark~多谢楼主详尽的叙述~辛苦了
之前一直有个想法把OUF弄懂..然后在NGA上面发个基本的教学帖..一直也没时间跟精力学这个.API好像也没查阅的地方..LZ已经做出来了..先赞一个...
支持下楼主,虽然已经改过好多头像,但有些OUF的东西还是没理解透彻,期待楼主的继续。
非常好的教学贴 努力学习.
这个,造福大众的大好事啊,不能不支持!
给楼主一个建议作为一个初学者我最希望看到楼主实例讲解比如我在论坛发的求助贴里面要求“oUF_Drk”头像框的一些具体要求[url]/read.php?tid=4105672[/url]具体读LUA,具体怎么改LUA我在前面是想添加宠物的BUFF显示现在又想把小队位置改到习惯的屏幕的左手边,就不知道如何下手了。望楼主实战讲解。
[align=center][size=200%][url=/read.php?tid=4107042&_ff=200&page=1]---------------接以上------------------[/url][/size][/align]
[b][size=120%]3.4 self.Debuffs/self.Buffs/self.Auras[/size][/b]首先要区分的是, oUF auras.lua里实现的一般挂靠在头像周围的状态图标栏,
和默认界面右上 的那几排Buff/Debuff图标是不同的两样东西.至少目前为止,oUF auras还不能替代右上的玩家状态栏.简单来说,这是因为oUF一直没有实现用鼠标右击取消buff的功能.可能haste大神认为这个功能太专注于玩家对象, 如果在本体内存在,有违unit通用性.在头像周围设置状态图标栏有两种方式,第一种是 debuffs和buffs分开,构建两个独立的框架.
第二种是建立一个buffs/debuffs混排的框架,也就是auras,先显示buff图标,然后紧接着跟上debuff图标.(aura是debuff和buff统称). 第一种方式外观上更清晰一些,也为更多数的插件所采用.
三种框架debuffs/buffs/auras在设置层面上,几乎一样,就拎出Debuffs来重点介绍. 在外观上, 对象self.Debuffs代表安置减益效果图标的总框体.
在内部结构上,self.Debuffs呈现为这样的一张表: 其数组成分储存 框内显示的各debuff图标对象 , i.e. self.Debuffs[index] (index = 1,2,3...) 为一个图标对象; 哈希表成分包含了控制图标外观组织的参数, 和自定义的一些功能函数. 外观参数 [color=red]debuffs.size[/color] 图标大小. 默认16[color=red]debuffs.initialAnchor[/color] POINT值,定位每个图标时,选定的对齐点(对齐于图标框上同一对起点)
默认&BOTTOMLEFT&[color=red]debuffs.[&growth-x&][/color] 图标在横轴上的排列方向. 值:&LEFT& &RIGHT&
默认&RIGHT&[color=red]debuffs.[&growth-y&][/color] 图标在竖轴上的排列方向(产生多行时). 值:&DOWN& &UP&
默认&UP&[color=red]debuffs.spacing[/color]
(可以在横轴, 竖轴分别设定 debuffs['spacing-x'] , debuffs['spacing-y'])[color=red]debuffs.num[/color] 最多显示图标数 (默认为40个)[color=red]debuffs.showType (debuffs.showDebuffType, buffs.showBuffType)[/color]
布尔值,是否根据类型着色(诅咒 魔法 毒药)[color=red]debuffs.filter[/color]
状态效果过滤,
由以下字段中一个或几个(以&|& AND关系) 组成,如&HARMFUL|PLAYER& 只显示玩家施放的减益: &&[list]&CANCELABLE & 可被取消的状态&&&HARMFUL&
减益(注意,若要在debffs中设置filter,请包括&HARMFUL&)&&&HELPFUL&
增益(同上,在buffs中设置时,必须包括)&&&NOT_CANCELABLE&
不可取消&&&PLAYER&
玩家施放的状态效果&&&RAID&
在和&HARMFUL&连用时,只显示玩家可驱散的减益, 和&HELPFUL&连用时,则为玩家可施加(于队友)的增益.&&[/list]状态效果栏的整体位置和行列数, 可以用debuffs.SetPoints()和debuffs.SetSize() 直接控制,不用多说.使用self.Auras混排状态栏时, 还可以用到几个参数:[color=red]auras.numBuffs[/color]
增益效果图标的最多显示数[color=red]auras.numDebuffs[/color] 减益效果图标最多显示数[color=red]auras.gap[/color] 增益和减益效果之间是否留空隔开-- [align=center][b][size=150%]4. 事件与挂载更新(Event , PreUpdate & PostUpdate )[/size][/b][/align]之所以在最后还得沾惹到令大家讨厌的事件问题, 是因为总有那么一些东西 被插件作者钉在地板之下. 如果遇到有的问题, 实在找不到参数来修改解决,那就得挖出样式元素的事件刷新(重绘)函数来看了.事件处理是oUF精髓之处, 在标签那一节中已小露锋芒, 头像框体整体的事件结构,更是出了奇的简练,所以也并不难理解.[color=blue]首先,oUF的头像对象在其内部,为每一个&可涉及&的事件制定一张处理表.[/color]如:[color=red]self['UNIT_HEALTH'] = {...}, self['UNIT_SPELLCAST_START'] = {...}, etc.[/color]这些事件表和表值都来自于样式元素.
每种样式元素的定义中包含了自己的 刷新函数Update() 和 响应事件event(s). 一旦响应事件有触发,就必须执行该元素的Update(), 重新绘制一遍元素的外观.[color=blue]在为头像载入每个样式元素的同时, oUF会将此元素的Update()塞进 与其响应事件对应的 事件处理表self[event]中.[/color] 看一个简单的例子:self.Auras 状态栏元素.
在auras.lua中,刷新函数Update() --完成一次对所有debuff和buff图标的生成与排列; 响应事件:
UNIT_AURA .那么载入self.Auras 元素的时候,
oUF查找 self['UNIT_AURA'] 是否存在,如果不存在,建立之,并且为self注册'UNIT_AURA'事件, 然后将auras.lua中的Update() 塞到表self.['UNIT_AURA']中去.然后就轻松了, 有了事件处理表之后, 头像框体self就掌握了它所有样式元素的更新控制.
响应过程极简单, self只设定了'OnEvent'的Script : 有任何event 触发时,
查找到self[event]表, 将event的事件参数 传递给这表中的每一个函数(即元素的Update(s)),各执行一遍. 也就是与此事件相关的元素,都刷新一次. 可参观一下 头像事件响应的代码 :[code=lua]Private.OnEvent = function(self, event, ...)
-- 只有一个OnEvent, 对所有注册过的事件&&if(not self:IsShown()) then return end
假如头像没有显示, 忽略事件&&return self[event](self, event, ...)
提取事件处理表 , 对表中每一个函数, 传递事件参数 并调用.
endlocal event_metatable = {
-- 这是实现 对表 函数调用的metatable . 纯粹lua知识.&&__call = function(funcs, self, ...)&&&&for _, func in next, funcs do&&&&&&func(self, ...)&&&&end&&end,}[/code]oUF就是用这种巧妙的事件处理结构, 既实现了强大而友好的扩展性(elements) , 又保持住了只用一个对象监视事件的高效.[color=red][b]PreUpdate & PostUpdate[/b][/color]回到本节开始的问题,样式函数中不能直接找到解决办法的话, 最后一个要找的地方就是这个样式元素的刷新函数Update.但插件作者一般不会直接动元素的Update,而是定义它的两个挂载:PreUpdate和PostUpdate.[color=blue]所有oUF样式元素的Update 都有一个共性,就是都会在函数体内的头部和尾部 分别检查用户有没有定义element.PreUpdate和element.PostUpdate, 如有定义则相应位置调用之. [/color]PreUpdate意思就是在元素内置刷新体之前预处理, PostUpdate则在内置刷新体之后补处理.
这样用户可以在样式元素刷新中加入自己的处理.oUF不遗余力的增强自己的扩展性, Pre/PostUpdate解除了用户在单个元素功能实现上的限制(在暴雪安全机制范围内).你让血量数字在每次伤血时,在屏幕上飞一圈都有可以. 这种应用方式非常灵活,本文不可能涵盖全,只能举一个具体的例子————修改Tukui能量值显示字样:Tukui的目标能量值 对npc和boss都不显示. 对某些需要监视boss能量值的战斗就很麻烦,比如四魔像和四风. 我们现在要把它改成对npc和boss也常驻显示. 已知控制能量值的元素参数应该是power.value, 刚开始猜想可能是用self:Tag(power.value,&....&)这样的标签形式, 但在Share()函数体内搜索无果. 那这时候就该查询power.PreUpdate或power.PostUpdate有无定义了,果然, power.PostUpdate = T.PostUpdatePower. 找到tukui/core/functions.lua 里的T.PostUpdatePower :[code=lua]T.PostUpdatePower = function(power, unit, min, max)
PostUpdate和PreUpdate的参数表由样式元素内置Update决定,这里由Update()传递进来的min,max分别指向 刷新时 unit当前能量值和最大能量值&&local self = power:GetParent()&&&&&&&&&&&&--
获得power的父框架,即头像框体self&&local pType, pToken = UnitPowerType(unit)&&&&&&--
获得能量类型&&local color = T.oUF_colors.power[pToken]&&&&&&-- 根据能量类型获得颜色值 (此颜色表与3.2节中为状态条染色用到的相同)&&if color then&&&&power.value:SetTextColor(color[1], color[2], color[3])
-- 将value染色,这里用的是FontInstance的API&&end&&if not UnitIsPlayer(unit) and not UnitPlayerControlled(unit) or not UnitIsConnected(unit) then&&&&power.value:SetText()
非玩家操控单位 或玩家断线, 能量值置空 !
按我们要求,将原来的value置空操作 改成 显示百分比, 但须考虑max为零的状况,所以须条件判断:
power.value:SetText()
if max & 0 then power.value:SetFormattedText(&%d%%&, floor(min / max * 100))&&--
然后把玩家断线的判断剪切掉, 换到下面一个elseif 里去. &&&&elseif UnitIsDead(unit) or UnitIsGhost(unit) then&&&&power.value:SetText()
玩家角色死亡或鬼魂状态, 能量值置空; 修改后 then 前加入 or not UnitIsConnected(unit)&&else&&--......[/code][b]后记[/b]: 因为oUF还在不断更新,外加文中还可能有错误之处 需要大家指正,
所以只能说 一期工程到此结束.
起名的时候有点自大了, 现在看那&通用&两字比较惭愧.有很多老成作品,比如oUF_Diablo,在oUF骨架的基础上添加了很多自己的东西,甚至颠覆了很多惯用法,那篇幅所限,对此就力不从心了.请大家原谅.
不过真正要驾驭oUF插件 甚至能编写出自己的Layout,还须自己实战.
写这篇文章的意义就变成了,启发更多的同学开始自己的oUF探索之路. 做插件玩家,其实也很开心,我虽然没有平面功底,设计不出好的layout,但一直在摆弄Lua,觉得玩游戏能有这样的收获,也是一件幸事.[quote]参考资料和网站(都是不错的学习资料):[list] [*][url=/haste/oUF]oUF作者 Haste 的源码发布站 [/url]
[*][url=/docs]&World of Warcraft Programming, 2nd edition&(第三部分对暴雪安全机制的解释很全面) 及官网资料库 [/url]
[*][url=http://www.iriel.org/wow/docs/SecureHeadersGuide-4.0-r1.pdf]Iriel's Field Guide to Secure Handlers 介绍安全控制柄的文档[/url], [url=http://www.iriel.org/wow/docs/SecureHeadersGuide%20-%20pre1.pdf]3.0版本[/url]
[*][url=http://wow.go-hero.net/framexml/13750]暴雪FrameXML源码库,可在此查阅wow各版本API和XML的改动[/url]
[*][url=]wowwiki[/url]
[*][url=http://tukui.org/forums/]tukui论坛,尤其推荐其中guides / skins / Lua Script Help三个板块[/url]
[*] [url=http://pgl.yoyo.org/luai/i/about]另一本lua手册(比官方lua手册好很多,查api更方便)[/url][/list][/quote]--EOF
首页占楼....
支持下楼主,很好的给我们学习了下..

我要回帖

更多关于 暗黑风格头像插件 的文章

 

随机推荐