92
技術社區[雲棲]
《魔獸世界插件》教程—21點撲克遊戲 Blackjack
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
1
2
3
4
5
6
|
##
Author: Walle
##
Interface: 50400
##
Title: testButton
##
Version: 1.0
Frame.xml
Frame.lua
|
再看下xml,裏麵有兩個button
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
< Ui xmlns:xsi = "https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd = "https://www.w3.org/2001/XMLSchema" xmlns = "https://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等都有大小用下麵的來表示一個200×200的。
<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
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點來算,如果沒爆的話就是最佳值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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張。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
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次方)。比如一個64×128就是合格的圖片大小。
魔獸世界插件也支持音樂播放,好像支持mp3格式和ogg格式。大家可以用”格式工廠”軟件來轉換。播放音樂的API是PlaySoundFile,參數是路徑。
function InsurancePayMusic()
PlaySoundFile(“Interface\\AddOns\\BlackJack\\sounds\\ins_pay.ogg”)
end
8.這次做的插件下載地址
https://www.waitingfy.com/?attachment_id=1053
也可以訪問github地址:https://github.com/waitingfy/BlackJack
https://www.waitingfy.com/archives/1047
最後更新:2017-04-03 12:56:08