1.效果圖
因爲我是新手,只能做一個非常簡單的插件,21點撲克遊戲。比較有趣吧,插件也可以做一個遊戲?遊戲中的遊戲!
2.編寫魔獸世界插件準備
- 首先你要一個最新的魔獸世界客戶端,我的有26G大小。記得要申請一個試玩賬戶,試玩賬戶不會消耗遊戲時間,可不能用正常賬戶,那調試代碼燒點卡燒的厲害!
- 用什麼編輯器呢?魔獸世界插件大部分是Lua,一部分是XML,SciTE比較適合Lua,但我感覺用NotePad++比較好。前期可能要用下一個大型的編輯器叫"AddOn Studio for World of Warcraft",有點像VS。它用來調試XML不錯。
- 還要準備3個第三方魔獸世界插件來幫助我們!BugGrabber,BugSack,TinyPad。前面兩個是調試用的,如果我們寫的插件有錯誤的話會提示第幾行,什麼錯誤。TinyPad是一個遊戲內記事本功能的插件,可以在裏面寫Lua腳本,直接遊戲運行,當我們要測試少量的wow API比較有用
- 看完《Programming in Lua, 3rd Edition》和《Beginning Lua with World of Warcraft Add-ons》(真的看完就不用往下看這篇教程了=。=,對英語閱讀有一定要求,但不難)
- 比較有用的網站,www.google.com, www.wowwiki.com。暴雪是沒有公佈插件API的,只能google了。
總結下跟一般的編程一樣的。
運行效果查看:魔獸世界客戶端+試玩賬戶
編輯器:首推NotePad++,SciTE,AddOn Studio
調試:!BugGrabber,BugSack,TinyPad + print("") ,print 可以在遊戲中打印日誌,我們可以打印變量來調試。
教程:《Beginning Lua with World of Warcraft Add-ons》
當然不能每次重啓魔獸世界客戶端來看修改效果,我們可以做一個簡單的宏來重載所有UI,當你修改了你的插件的XML或者Lua文件時,可以重載所有UI來看到修改效果。當然Shift+點擊BugSack也有同樣的效果。修改toc或者新增圖片,音樂資源是不能靠重載UI來生效的,要重啓魔獸世界客戶端。
3.還是先寫一個插件版的Hello World吧
把上面提到的三個插件!BugGrabber,BugSack,TinyPad,google下,都下載下來。拷貝到\Interface\AddOns 目錄下。進入遊戲,輸入/pad 就可以打開TinyPad了,我們輸入print("Hello World"),再點擊上面的菜單有個功能是run this page as a script,就可以看到效果了。
4.寫一個簡單插件界面吧
點擊Click按鈕就會調用我們一個Lua函數,點擊Close,整個界面就會隱藏。
這次是一個完整的插件,名字叫testButton,包括三個文件:
Frame.lua -- 用來存放腳本
Frame -- 用來描述界面,以XML編寫
testButton.toc -- 用來描述我們的插件,比如插件支持的魔獸世界版本,插件名字,插件作者,插件包含文件等等。
先來看下testButton.toc
## Author: Walle
## Interface: 50400
## Title: testButton
## Version: 1.0
Frame.xml
Frame.lua
再看下xml,裏面有兩個button
<Ui xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.blizzard.com/wow/ui/">
<Frame name="Frame1" parent="UIParent" toplevel="true" enableMouse="true" movable="true" clampedToScreen="true">
<Size>
<AbsDimension x="200" y="200" />
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset x="-35" y="34" />
</Anchor>
</Anchors>
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
<BackgroundInsets>
<AbsInset left="11" right="12" top="12" bottom="11" />
</BackgroundInsets>
<TileSize>
<AbsValue val="32" />
</TileSize>
<EdgeSize>
<AbsValue val="32" />
</EdgeSize>
</Backdrop>
<Frames>
<Button name="BtnClose" inherits="UIPanelButtonTemplate" text="Close">
<Size>
<AbsDimension x="75" y="23" />
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset x="69" y="-134" />
</Anchor>
</Anchors>
<Scripts>
<OnClick>
self:GetParent():Hide()
</OnClick>
</Scripts>
</Button>
<Button name="BtnClick" inherits="UIPanelButtonTemplate" text="Click">
<Size>
<AbsDimension x="75" y="23" />
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset x="69" y="-100" />
</Anchor>
</Anchors>
<Scripts>
<OnClick>
BtnClick()
</OnClick>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnLoad>
self:RegisterForDrag("LeftButton")
</OnLoad>
<OnDragStart>
self:StartMoving()
</OnDragStart>
<OnDragStop>
self:StopMovingOrSizing()
</OnDragStop>
</Scripts>
</Frame>
</Ui>
這個XML看起來有點複雜,可以用Addon Studio 建一個項目,拖個按鈕進去,玩玩。就大致瞭解上面的東西了。無論是Frame還是Button等都有大小用下面的來表示一個200x200的。
<Size><AbsDimension x="200" y="200" />
</Size>
Anchors 來表示位置。point可以設置CENTER,TOP,LEFT等等,下面的Offset是偏移量,比如你設置了CENTER,那麼-35就是中心偏左35。
<Anchors>
<Anchor point="CENTER">
<Offset x="-35" y="34" />
</Anchor>
</Anchors>
Backdrop表示Fram的邊框,直接從Addon Studio抄下來。
我們注意到Button有個屬性是inherits,繼承的意思
inherits="UIPanelButtonTemplate" 這裏表示簡單的繼承了WOW原生的按鈕樣式,按鈕可以設置非常複雜的樣式,這裏不再贅述,大家可以參考WOW API。
XML中都可以加腳本,比如這裏:
<Scripts>
<OnClick>
self:GetParent():Hide()
</OnClick>
</Scripts>
它的效果就是簡單的使整個都隱藏起來。
我們對整個Frame還增加了拖動效果。
還有必須說明的是一般用XML能實現的,直接用Lua代碼也可以的。
比如設置寬度,高度,可以這樣寫:
Frame1:SetWidth(500)
Frame1:SetHeight(500)
大家可以在tinypad中,執行看下效果。不單單是改變屬性,創建一個按鈕也可以用Lua代碼的。大家可以去Google。
最後看下Frame.lua
它裏面就是一個簡單的function:
function BtnClick()
print ("BtnClick")
end
testbutton項目下載: http://www.waitingfy.com/?attachment_id=1058
5.還是先介紹下21點的遊戲規則
回到我們的撲克遊戲來。
懂的童鞋就直接可以跳過了,容我摘抄一段:
21點一般用到1-8副牌。莊家給每個玩家發兩張牌,一張牌面朝上(叫明牌),一張牌面朝下(叫暗牌);給自己發兩張牌,一張暗牌,一張明牌。大家手中撲克點數的計算是:K、Q、J 和 10 牌都算作 10 點。A 牌既可算作1 點也可算作11 點,由玩家自己決定。其餘所有2 至9 牌均按其原面值計算。首先玩家開始要牌,如果玩家拿到的前兩張牌是一張 A 和一張10點牌,就擁有黑傑克(Blackjack);此時,如果莊家沒有黑傑克,玩家就能贏得2倍的賭金(1賠2)。如果莊家的明牌有一張A,則玩家可以考慮買不買保險,金額是賭籌的一半。如果莊家是blackjack,那麼玩家拿回保險金並且直接獲勝;如果莊家沒有blackjack則玩家輸掉保險繼續遊戲。沒有黑傑克的玩家可以繼續拿牌,可以隨意要多少張。目的是儘量往21點靠,靠得越近越好,最好就是21點了。在要牌的過程中,如果所有的牌加起來超過21點,玩家就輸了——叫爆掉(Bust),遊戲也就結束了。假如玩家沒爆掉,又決定不再要牌了,這時莊家就把他的那張暗牌打開來。一般到17點或17點以上不再拿牌,但也有可能15到16點甚至12到13點就不再拿牌或者18到19點繼續拿牌。假如莊家爆掉了,那他就輸了。假如他沒爆掉,那麼你就與他比點數大小,大爲贏。一樣的點數爲平手,你可以把你的賭注拿回來。
沒做這個遊戲之前我也大致知道21點遊戲規則,沒有想到還有個保險的東西。大家可以去搜下有關21點的flash遊戲來玩下。
6.Lua基礎教程
老實說,我寫這個插件不是爲了寫一個幫助的插件,是想要學習下Lua的語法。所以看《Programming in Lua, 3rd Edition》就很有必要。
下面只是列舉下一些非常基礎的Lua語法,用來做我們這次《21點撲克遊戲》足夠用了。21點撲克遊戲,我寫了一個函數來得到手裏牌的總的值。我們知道A這個牌比較特殊,即可當1,也可做11,但不可能有兩張牌都作爲11,總的就是>=22就爆掉了。下面這個函數比較簡單,先嚐試循環所有的牌,對值相加,如果沒有A的話就直接返回,如果有A的話,嘗試把它以11點來算,如果沒爆的話就是最佳值。
function GetTotalValue(cards)
local containAce = false --//變量用local關鍵詞,沒有local就是全局變量
local totalValue = 0
local anotherTotalValue = 0
for i, v in ipairs(cards) do --//for 循環
totalValue = totalValue + v.value
if v.value == 1 then --//if 列子
containAce = true
end --//if 結束
end --//for 循環結束
if containAce then
anotherTotalValue = totalValue + 10 --// change Ace's value to 11
end
if containAce and anotherTotalValue <= 21 then
return anotherTotalValue
end
return totalValue
end
簡單解釋下就是Lua中可以以一行作爲結束,都不用加;,局部變量前綴是local,有點像Javascript中的var,但Lua的Local也可以直接不寫就是全局變量了。Lua會有很多end,for循環結束有end,if結束也有end,function結束也是end。C++ 中的 && 和 || 在 Lua中是 and 和 or,另外 C++中的 != 在 Lua 中是 ~=
Lua中最重要的就是Table,它沒有Javascript中的Array,但這個Table比Array還要強大。再來看一個例子,是我們這個遊戲的初始化牌的方法。總共牌共有52張。
POKER_CARD_NAME = "%s of %s"
POKER_CARDS = { --//Table好像內部是一個hashtable,所以可以這樣用。這樣POKER_CARDS["K"] 就== "King"了
K = "King",
Q = "Queen",
J = "Jack",
["10"] = "Ten",
["9"] = "Nine",
["8"] = "Eight",
["7"] = "Seven",
["6"] = "Six",
["5"] = "Five",
["4"] = "Four",
["3"] = "Three",
["2"] = "Two",
A = "Ace",
}
POKER_SUITS = {
H = "Hearts",
D = "Diamonds",
C = "Clubs",
S = "Spades",
}
local ranks = {"K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3", "2", "A"} --//也可以直接初始話這樣,index是用1開始的比較奇怪。
local suits = {"H", "D", "C", "S"}
local cards = {}
local cardsByRank = {}
local value = 10
for i, r in ipairs(ranks) do
cardsByRank[r] = {}
for i, s in ipairs(suits) do
cards[#cards + 1] = { --// #cards可以得到cards這個table的長度,這裏每個card又是一個table
rank = POKER_CARDS[r],
suit = POKER_SUITS[s],
name = POKER_CARD_NAME:format(POKER_CARDS[r], POKER_SUITS[s]), --//string類型中有簡單的format語法
code = r..s,
value = value
}
cardsByRank[r][s] = cards[#cards]
end
if i >= 4 then
value = value - 1
end
end
7.再講下別的注意事項
我們這個插件遊戲中,需要用到撲克的圖片。魔獸世界插件是支持圖片顯示的,用Frame中的texture就可以了。具體大家可以看代碼,圖片格式支持兩種,一種是TGA,另外一種我忘了。圖片大小比較變態,要(2的n次方) x (2的n次方)。比如一個64x128就是合格的圖片大小。
魔獸世界插件也支持音樂播放,好像支持mp3格式和ogg格式。大家可以用"格式工廠"軟件來轉換。播放音樂的API是PlaySoundFile,參數是路徑。
function InsurancePayMusic()
PlaySoundFile("Interface\\AddOns\\BlackJack\\sounds\\ins_pay.ogg")
end
8.這次做的插件下載地址
記得進入遊戲記得要先輸入/bj 才能打開這個插件,默認是隱藏的。
http://www.waitingfy.com/?attachment_id=1053
也可以訪問github地址:https://github.com/waitingfy/BlackJack
參考:
《Programming in Lua, 3rd Edition》
《Beginning Lua with World of Warcraft Add-ons》