廣告廣告
  加入我的最愛 設為首頁 風格修改
首頁 首尾
 手機版   訂閱   地圖  簡體 
您是第 3631 個閱讀者
線上遊戲 快速索引
RF CSO LUNA 墨香 尋仙 暗黑 洛汗 運命 希望 仙劍 誅仙2
天堂 天堂2 SD鋼彈 勁舞團 爆爆王 三國志 楓之谷 QQ三國 魔物獵人 夢幻誅仙 烈日風暴 劍俠世界
艾爾之光 天子傳奇 中華英雄 幸福五角 永恆紀元 天翼之鍊 熱血江湖 戀愛盒子 吞食天地 吞食天地2 光明戰記 天龍八部
戰慄時空 第九封印 完美世界 仙境傳說 魔獸世界 星海爭霸2 無盡的任務2 極速快車手 武林群俠傳 全民打棒球 跑跑卡丁車 SF特種部隊
三國群英傳 未來啟示錄 暗黑破壞神 真三國無雙 夢幻龍族傳說              

 
發表文章 發表投票 回覆文章
  可列印版   加為IE收藏   收藏主題   上一主題 | 下一主題   
imiss 手機
個人頭像
個人文章 個人相簿 個人日記 個人地圖
特殊貢獻獎
初露鋒芒
級別: 初露鋒芒 該用戶目前不上站
推文 x1 鮮花 x106
分享: 轉寄此文章 Facebook Plurk Twitter 複製連結到剪貼簿 轉換為繁體 轉換為簡體 載入圖片
推文 x0
[UI/巨集] ADDONS編寫普及(轉貼)
難得一見的好文:)
對瞭解UI有一定程度的幫助唷

BY imiss

為了感恩原作者大大的辛勞,所以特此轉載此貼,讓更多的玩家一起加入UI製作者行列:)原文將不做任何修改

作者:WOWAR。英雄
前言
22號基本寫完。比預計的要快

這個不是數學書或者語文書。我不想也沒有那個能力寫成那樣……
所以請抱著看小說的態度來看。

因為ADDONS的編寫是一個整體。我實在無法分清哪個是要先說,哪個是要後說
所以有看不懂的地方就跳過去。接著看下面

前幾層樓寫的相對詳細些。後幾層樓更多的是提示。我還是希望看官能自己分析,自己動手研究

最後。短短的6層樓包含了我半年的心血,而且我語文課真的是沒好好去上
所以如果一時看不懂。請多讀幾遍 或者回帖指出,我會盡力解釋的

Addons (Add-Ons)
中文直譯:附件,附加 附加軟體。 俗稱:插件

解釋:他們是一些附加的檔,被放置在玩家 WOW 遊戲目錄下的 Interface 檔夾中。插件 使用暴雪提供的LUA和XML代碼(官方API函數介面)來擴充玩家可以使用的用戶介面功能。

插件是通過(暴雪提供的)LUA和XML檔(函數)構成的,並且也是通過暴雪的編譯機所解釋和執行的。因此,暴雪也不會封停任何使用插件的玩家。

StatusBar
在之前我們大概知道了ADDONS的一些基本概念

那麼現在。在各種類型的框體中挑一個StatusBar來說說

基本概念
StatusBar:是WOW中用來定義類似施法條。進度條之類的一種框體,
說白了就是可以根據某個數值,即時的改變條條的長短

一個StatusBar有3個重要的參數
1、最大長度 maxValue
2、最小長度 minValue
3、當前長度 Value

要動態的改變StatusBar就需要用腳本(Scripts)中的事件即時的設置當前長度(Value)
(這句話可能有點饒口。不過我就這點語文水準了…見諒見諒)

準備工作

首先根據我們之前的概念。一個TOC檔是必不可少的,編個first.toc
## Interface: 1600
## Title: 我的第一插件
## Notes: 真的是我的第一插件哦

然後我們當然得用XML來定義StatusBar這個框體,那麼編寫個first.xml
不過WOW並不知道我們寫了first.xml這個檔。我們得告訴他。所以在first.toc中加一句(紅色的部分)
## Interface: 1600
## Title: 我的第一插件
## Notes: 真的是我的第一插件哦
first.xml

好了 正式開始編寫first.xml

按照基本的XML檔格式 先寫好基本的嵌套
<StatusBar>
</StatusBar>

起個好名字
<StatusBar name="haomingzi">
</StatusBar>

注意紅色的那句。現在我們名叫haomingzi的StatusBar 會根據變數SVALUE自動改變長短了
(這裏我們用到了腳本。後面會詳細解釋的。先記得<Scripts>是腳本就可以了)
<StatusBar name="haomingzi">
          <Scripts>
                <OnUpdate>
                    haomingzi:SetValue(SVALUE);
                </OnUpdate>
          </Scripts>
</StatusBar>

現在我們把變數SVALUE設置為玩家的血量
那麼:
<StatusBar name="haomingzi">
          <Scripts>
                <OnUpdate>
                    haomingzi:SetValue( UnitHealth("player") );
                </OnUpdate>
          </Scripts>
</StatusBar>
OK。一個玩家的HP條就寫出來了

當然僅僅這幾行還遠遠不夠,繼續完善下
先把最大和最小長度定義好
<StatusBar name="haomingzi" minValue="0" maxValue="100">
          <Scripts>
                <OnUpdate>
                    haomingzi:SetValue( UnitHealth("player") );
                </OnUpdate>
          </Scripts>
</StatusBar>

這裏我們設置的是0到100。顯然玩家的血量肯定不會在0到100之內的。
那麼我們就要把他轉換為百分比
<StatusBar name="haomingzi" minValue="0" maxValue="100">
          <Scripts>
                <OnUpdate>
                    local SVALUE=( UnitHealth("player") / UnitHealthMax("player") )*100
                    haomingzi:SetValue(SVALUE);
                </OnUpdate>
          </Scripts>
</StatusBar>

設定下他的位置,比方把他放在螢幕的中間
(具體的如何設置位置。在樓下會講。現在只要知道紅色部分的代碼是設定位置就可以了)
<StatusBar name="haomingzi" minValue="0" maxValue="100">
          <Anchors>
                <Anchor point="center" relativeTo="UIparent" relativePoint="center"/>
          </Anchors>
          <Scripts>
                <OnUpdate>
                    local SVALUE=( UnitHealth("player") / UnitHealthMax("player") )*100
                    haomingzi:SetValue(SVALUE);
                </OnUpdate>
          </Scripts>
</StatusBar>

設定一下大小
<StatusBar name="haomingzi" minValue="0" maxValue="100">
          <Size>
                <AbsDimension x="70" y="8"/>
          </Size>
          <Anchors>
                <Anchor point="center" relativeTo="UIparent" relativePoint="center"/>
          </Anchors>
          <Scripts>
                <OnUpdate>
                    local SVALUE=( UnitHealth("player") / UnitHealthMax("player") )*100
                    haomingzi:SetValue(SVALUE);
                </OnUpdate>
          </Scripts>
</StatusBar>

當然他長什麼樣子我們還沒弄呢~
<StatusBar name="haomingzi" minValue="0" maxValue="100">
          <BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
          <Size>
                <AbsDimension x="70" y="8"/>
          </Size>
          <Anchors>
                <Anchor point="center" relativeTo="UIparent" relativePoint="center"/>
          </Anchors>
          <Scripts>
                <OnUpdate>
                    local SVALUE=( UnitHealth("player") / UnitHealthMax("player") )*100
                    haomingzi:SetValue(SVALUE);
                </OnUpdate>
          </Scripts>
</StatusBar>
最後給頭尾加上最基本的<ui></ui>嵌套。就大功告成了
<ui>
<StatusBar name="haomingzi" minValue="0" maxValue="100">
          <BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
          <Size>
                <AbsDimension x="70" y="8"/>
          </Size>
          <Anchors>
                <Anchor point="center" relativeTo="UIparent" relativePoint="center"/>
          </Anchors>
          <Scripts>
                <OnUpdate>
                    local SVALUE=( UnitHealth("player") / UnitHealthMax("player") )*100
                    haomingzi:SetValue(SVALUE);
                </OnUpdate>
          </Scripts>
</StatusBar>
</ui>

進階
StatusBar除了SetValue這個重要的命令以外。還有個SetStatusBarColor命令。是用來改變顏色的

比如還是上面的例子
我們現在想當HP超過50%的時候為綠色 低於50%的時候為紅色
那麼先定義一個函數 就叫haomingzi_OnUpdate把 用來實現上面的功能
function haomingzi_OnUpdate()
local SVALUE=( UnitHealth("player") / UnitHealthMax("player") )*100;
if SVALUE > 50 then
    haomingzi:SetStatusBarColor(1,0,0);
end
end

然後我們在腳本中調用這個函數就可以了
<ui>
<StatusBar name="haomingzi" minValue="0" maxValue="100">
          <BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
          <Size>
                <AbsDimension x="70" y="8"/>
          </Size>
          <Anchors>
                <Anchor point="center" relativeTo="UIparent" relativePoint="center"/>
          </Anchors>
          <Scripts>
                <OnUpdate>
                    haomingzi_OnUpdate();
                </OnUpdate>
          </Scripts>
</StatusBar>
</ui>
更多的框體
當然框體絕對不僅僅只有<StatusBar>這一中。還有諸如<Button> <Frame> <Texture> <FontString>等等等等
這裏就不一一解釋了,你隨便打開一個寫好的ADDONS都可以發現他們的身影。自己分析一下把

位置

這裏將說說 如何定義一個框體的位置

我們打開任意的一個編寫好的ADDONS的XML檔。多半會發現形如這樣的代碼
CODE:     [Copy to clipboard]
<Anchors>   <Anchor point="CENTER" relativeTo="Minimap" relativePoint="CENTER">     <Offset>         <AbsDimension x="55" y="-55"/>     </Offset>   </Anchor></Anchors>


這樣的代碼就是用來定義的位置的

數學課和物理課都上過把?(雖然我很討厭我們過去的數學老師 ><)
想知道任何一個物體的位置。只要有一個固定的參考物。再有與參考物體的相對座標。就可以了
---------------------------------------------------------------------------------------------------
先來點基本概念

我們用一個方框來表示框體,那麼

                TOP
  TOPLEFT     --------------------     TOPRIGHT
          |             |
  LEFT       |     CENTER     |     RIGHT
          |             |
BOTTOMLEFT   --------------------     BOTTOMLEFT
                      BOTTOM

應該有點頭緒了把?
之前那段代碼的意思就是 把位置定義在
小地圖的中心點和我們的框體的中心點X座標為55 Y座標為55的地方

如果看不明白這句話 不要緊 我們一句一句的來分析
------------------------------------------------------------------------------------------------------
具體分析

頭一句和最後一句
<Anchors>
</Anchors>
這個嵌套是告訴WOW:中間的代碼是定義位置

第二句和倒數第二句
  <Anchor point="CENTER" relativeTo="Minimap" relativePoint="CENTER">
  </Anchor>
這個嵌套就是告訴WOW 我們開始定義位置了。

先看第二句。
point="CENTER" 參考之前我畫的那張很醜陋的圖。
意思就是:要定義位置的框體(為了描述方便。以下簡稱為框體A)的中心點(CENTER)作為定義點。
(定義點這個名詞是我杜撰的。如果不明白。先接著往下看)

relativeTo="Minimap"
意思就是:給我們的框體A設置一個參考物(為了描述方便。以下把參考物簡稱為框體B)
在這裏。就是把框體B設置為小地圖(Minimap)

relativePoint="CENTER"
同樣的。也得給我們的框體B設置一個定義點
在這裏。就設置為中心點(CENTER)

現在解釋一下定義點這個我杜撰的名詞
為什麼要有定義點這個概念呢?
因為所有的框體都不是一個點。而是一個平面。而相對座標只能是點與點的座標。所以就必須在框體上找一個點來定義座標
而這個點。就是我所謂的定義點
至於一個框體的定義點可以設置為那些,參考上面我畫的那張醜陋的圖

搞明白了以上的概念。那麼中間的那段代碼
CODE:     [Copy to clipboard]
    <Offset>         <AbsDimension x="55" y="-55"/>     </Offset>


也就不難理解是什麼意思了。這正是設置2個定義點之間的相對座標
-------------------------------------------------------------------------------------------------------
進階
為什麼一向崇尚操作簡單的暴雪要把位置的定義弄的這麼複雜呢?
似乎我們只要變換2個定義點之間的相對座標。那麼無論我們把定義點怎麼設置 都可以達到同樣的效果
其實。是因為框體的大小有時候是不固定的。

比如我想實現這樣的效果:
在玩家血條的左邊顯示HP的具體數值
如果這麼定義位置:
CODE:     [Copy to clipboard]
<FontString name="HPText"><Anchors>   <Anchor point="CENTER" relativeTo="PlayerFrame" relativePoint="CENTER">     <Offset>         <AbsDimension x="55" y="0"/>     </Offset>   </Anchor></Anchors>     。   。   。   。


似乎可以到達效果,
可是HP有多有少。
當HP為3位數的時候。數值是在血條的左邊。但是但HP為4為數的時候。數值就超過了左邊擋主了部分血條。

所以。得這麼寫
CODE:     [Copy to clipboard]
<FontString name="HPText"><Anchors>   <Anchor point="RIGHT" relativeTo="PlayerFrame" relativePoint="LEFT">     <Offset>         <AbsDimension x="0" y="0"/>     </Offset>   </Anchor></Anchors>     。   。   。   。


這樣。無論HP為多少。數值的右側永遠都和血條的坐側對齊
---------------------------------------------------------------------------------------------------------------
PS:
當相對座標為0,0的時候。代碼可以簡化
比如剛才的代碼可以簡化為
CODE:     [Copy to clipboard]
<FontString name="HPText"><Anchors>   <Anchor point="RIGHT" relativeTo="PlayerFrame" relativePoint="LEFT"/></Anchors>



  。
  。
  。
注意:別漏看了第三句最後的那個反斜杠

腳本

看到這裏。我們對框體的定義應該有了很大的瞭解。現在定義一個自己的框體應該沒什麼難度了把?
在STATUSBAR部分我們提到了腳本。
腳本我個人覺得是ADDONS的精髓
弄懂了腳本部分。那麼去他的FLEXBAR 去他的DAB 去他的DUF 我們不需要了。我們自己就可以來做了

基本概念
什麼是腳本。通俗的說:腳本就是告訴框體在什麼時候執行什麼命令

同樣的
我們用<Scripts></Scripts>這樣的嵌套來表示代碼中腳本的部分

具體的舉個例子
還記得FLEXBAR或者DAB一個很實用的功能把?當滑鼠進入按扭的區域 按紐顯示 離開則隱藏
現在我們直接在ADDONS中寫(為了描述方便起見 以下只寫出代碼中我們需要注意的部分)
<BUTTON name="button_1">
    <Scripts>
          <OnEnter>
                This:Show();
          </OnEnter>
          <OnLeave>
                This:Hide();
          </OnLeave>
    </Scripts>
</BUTTON>

<OnEnter>這個嵌套就是滑鼠進入框體的區域需要執行的命令
<OnLeave>則是滑鼠離開框體的區域需要執行的命令
如何?是不是很簡單呢?

接著來。
FLEXBAR或者DAB還有很多神奇的功能。比如根據條件自動改變按扭的位置 透明度 縮放 等等等
如果我們直接在ADDONS中編寫也很方便
比如進入戰鬥狀態 自動出現按扭 反之隱藏
<BUTTON name="button_1">
    <Scripts>
          <OnLoad>
                this:RegisterEvent("PLAYER_ENTER_COMBAT");
                this:RegisterEvent("PLAYER_LEAVE_COMBAT");
          </OnLoad>
          <OnEvent>
                if (event == "PLAYER_ENTER_COMBAT") then
                    this:Show();
                elseif (event == "PLAYER_LEAVE_COMBAT") then
                    this:Hide();
                end
          </OnEvent>
    </Scripts>
</BUTTON>

<OnLoad>是框體被載入的時候需要執行的命令
這裏。我們給button_1這個框體註冊了2個事件:玩家進入戰鬥和玩家離開戰鬥

<OnEvent>是註冊的事件發生的時候需要執行的命令
這裏。我們用了一個判斷語句。
當事件為玩家進入戰鬥的時候 顯示按扭1 當事件為玩家離開戰鬥的時候 隱藏按扭1

同樣的
腳本和框體一樣 不可能僅僅只有我上面所說的那幾個。
更多的腳本需要你自己去發現。。我不想囉嗦了。

更多的驚喜
以上2個只是很簡單的例子。腳本中執行的命令還可以是相互調用。相互依存的來實現更多更複雜的功能
這時候。僅僅一個XML檔已經不能滿足我們的需要了。我們得在LUA檔中來編寫

LUA

如果你有耐心看完了上面的全部內容 並且親手去實驗了
那麼如何編寫一個XML檔應該了然與胸了把

當然一個精巧的ADDONS不可能僅僅只有XML檔而已。他還需要LUA檔

LUA檔當然就是用LUA格式寫的

具體的LUA的語法 限與帖子的篇幅,不能詳盡說明。好在現在網上的資料很多的

我只說幾個個人覺得很有用的部分

1。引用LUA和定義函數
先回頭看6樓的最後那段代碼
<BUTTON name="button_1">
    <Scripts>
          <OnLoad>
                this:RegisterEvent("PLAYER_ENTER_COMBAT");
                this:RegisterEvent("PLAYER_LEAVE_COMBAT");
          </OnLoad>
          </OnEvent>
                if (event == "PLAYER_ENTER_COMBAT") then
                    this:Show();
                elseif (event == "PLAYER_LEAVE_COMBAT") then
                    this:Hide();
                end
          </OnEvent>
    </Scripts>
</BUTTON>
我們可以把腳本的部分放到LUA中來寫。

首先我們新建一個BUTTON1.LUA文件
然後在XML檔裏面要告訴WOW 我們寫了BUTTON1.LUA文件
<Script file="BUTTON1.lua"/>
<BUTTON name="button_1">
    <Scripts>
          <OnLoad>
                this:RegisterEvent("PLAYER_ENTER_COMBAT");
                this:RegisterEvent("PLAYER_LEAVE_COMBAT");
          </OnLoad>
          <OnEvent>
                if (event == "PLAYER_ENTER_COMBAT") then
                    this:Show();
                elseif (event == "PLAYER_LEAVE_COMBAT") then
                    this:Hide();
                end
          </OnEvent>
    </Scripts>
</BUTTON>

定義函數的LUA命令是function
現在我們就把<OnLoad>和<OnEvent>這2個部分的命令定義為函數
function button_1_onload()
                this:RegisterEvent("PLAYER_ENTER_COMBAT");
                this:RegisterEvent("PLAYER_LEAVE_COMBAT");
end

function button_1_onevent(event)
                if (event == "PLAYER_ENTER_COMBAT") then
                    this:Show();
                elseif (event == "PLAYER_LEAVE_COMBAT") then
                    this:Hide();
                end
end

然後在XML檔中引用這2個函數
<Script file="BUTTON1.lua"/>
<BUTTON name="button_1">
    <Scripts>
          <OnLoad>
                button_1_onload();
          </OnLoad>
          <OnEvent>
                button_1_onevent(event);
          </OnEvent>
    </Scripts>
</BUTTON>
這樣原來的一個XML檔就被我們分成了2個檔 LUA和XML
也許就上面的那段簡單的代碼 我們還覺得這樣做並沒有什麼太大的意義
不過。當你寫了一段很複雜 很麻煩的代碼的時候。這麼做顯然有助與你簡化代碼和理清思路

2。代碼的本地化
因為WOW有很多國家的版本。所以一些變數的設置需要本地的語言。
比如能在中國使用的ADDONS,有時候並不能在美國使用。這時候我們就需要做一些本地化的工作

怎麼做?
我們把所有的需要使用當地語言的變數集中起來 在一個LUA檔中定義
(這個LUA檔。我們一般起名叫:localization.lua)
而且。WOW還提供了自動判斷語種的功能
這些都很簡單。隨便打開一個ADDONS的localization.lua自己看一看就明白 不囉嗦了

當然LUA的作用遠遠不止這些
畢竟LUA是一個很成熟的語言。熟練的運用將大大簡化我們的工作量
比如LUA的陣列功能。字串的判斷
更多的細節。可以在自己動手寫ADDONS的過程中慢慢摸索。

繼承

WOW已經幫我定義好了很多有用的框體
所以很多的時候。我們並不需要自己完全的重新定義
直接引用他們就可以了
這裏就要用到繼承這個概念

如何做?
繼承的命令是inherits

比如我想定義一個文字框體。他的樣子和顯示玩家的名字的文字的樣子是一樣的
那麼:
<FontString name="TEXT_FRAME" inherits="GameFontNormalSmall" >
<FontString/>

這樣 我們簡單的用了inherits="GameFontNormalSmall"命令
就把 TEXT_FRAME框體的大小 顏色 透明度 字體等等等等屬性全部搞定了

如果有不滿意的地方 還可以重新定義。
比如改變一下顏色
<FontString name="TEXT_FRAME" inherits="GameFontNormalSmall">
    <Color r="0" g="1" b="0"/>
<FontString/>
現在他就是綠色的咯

當然我們也可以定義自己的
這將大大有助於簡化我們的代碼。
還記得我以前寫的那個OPENDOOR嗎?
我在裏面一共定義了7個框體
其中有6個框體是按扭。並且他們很多部分都是公共的。

所以。如果我現在再來寫那個OPENDOOR 我會先寫一個父框 把6個按扭公共的部分全部寫進去
然後在一個一個的繼承就OK了。~

具體的父框的定義 不囉嗦了
大家可以隨便打開一個ADDONS 找到名字後面為Template的框體。那多半就是父框了。
動手分析一下把
(提示一點:在父框中的$parent就是要被繼承的子框的名字)



陪你進步、學習的好網站:http://typf.blogspot.com/
獻花 x0 回到頂端 [樓 主] From:台灣中華電信 | Posted:2005-10-20 09:59 |

首頁  發表文章 發表投票 回覆文章
Powered by PHPWind v1.3.6
Copyright © 2003-04 PHPWind
Processed in 0.055630 second(s),query:15 Gzip disabled
本站由 瀛睿律師事務所 擔任常年法律顧問 | 免責聲明 | 本網站已依台灣網站內容分級規定處理 | 連絡我們 | 訪客留言