《魔獸世界插件》教程---21點撲克遊戲 Blackjack

1.效果圖



因爲我是新手,只能做一個非常簡單的插件,21點撲克遊戲。比較有趣吧,插件也可以做一個遊戲?遊戲中的遊戲!


2.編寫魔獸世界插件準備

  1. 首先你要一個最新的魔獸世界客戶端,我的有26G大小。記得要申請一個試玩賬戶,試玩賬戶不會消耗遊戲時間,可不能用正常賬戶,那調試代碼燒點卡燒的厲害!
  2. 用什麼編輯器呢?魔獸世界插件大部分是Lua,一部分是XML,SciTE比較適合Lua,但我感覺用NotePad++比較好。前期可能要用下一個大型的編輯器叫"AddOn Studio for World of Warcraft",有點像VS。它用來調試XML不錯。
  3. 還要準備3個第三方魔獸世界插件來幫助我們!BugGrabber,BugSack,TinyPad。前面兩個是調試用的,如果我們寫的插件有錯誤的話會提示第幾行,什麼錯誤。TinyPad是一個遊戲內記事本功能的插件,可以在裏面寫Lua腳本,直接遊戲運行,當我們要測試少量的wow API比較有用
  4. 看完《Programming in Lua, 3rd Edition》和《Beginning Lua with World of Warcraft Add-ons》(真的看完就不用往下看這篇教程了=。=,對英語閱讀有一定要求,但不難)
  5. 比較有用的網站,www.google.com, www.wowwiki.com。暴雪是沒有公佈插件API的,只能google了。


總結下跟一般的編程一樣的。

運行效果查看:魔獸世界客戶端+試玩賬戶

編輯器:首推NotePad++,SciTEAddOn 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》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章