基本概念

變數(Variable)

如果把電腦的記體體當做是一連串的櫃子,那麼變數就像是已被使用並貼上標籤的櫃子,可讓使用者自由存取。其中,變數名稱就是貼上的標籤的名稱,變數的值就是櫃子裡存放的東西。所以:

  • 定義變數XXX,就好像在一個大房間裡,找一個沒有標籤的櫃子,貼上寫著「XXX」的標籤。(如果已經有個叫「XXX」的變數存在,我就不能再定義它。一般在這種情形下程式會出錯)

  • 設定XXX變數的值,就好像去找貼著「XXX」標籤的櫃子,把東西存放進去。

  • 取出XXX變數的值,就好像去找貼著「XXX」標籤的櫃子,把裡面的東西拿出來用。(不過電腦的世界和現實世界不太一樣,電腦拿完東西使用以後,東西不會消失,也就是說,讀取變數後,那個「XXX」櫃子裡的東西仍然存在。)

  • 修改XXX變數的值,就好像去找貼著「XXX」標籤的櫃子,把裡面的東西拿出來丟掉,再放一個新的東西進去。

變數有什麼用處呢?舉個例子來說,假設我在3分10秒時創造了一個英雄--死亡騎士阿薩斯。然後,我想設定「當遊戲進行到30分鐘時,巫妖王派遣二個末日守衛保護阿薩斯」,我當然要再創造二個末日守衛,可是地點呢?我有辦法告訴電腦地點是「3分10秒時創造的英雄的目前所在地」嗎?當然是沒有辦法的。為了解決這個問題,我必須在創造阿薩斯的時候,用變數把它記錄下來,假設變數叫做arthas,如此一來,在30分鐘時,我就可以叫電腦「創造二個末日守衛於arthas的目前位置」了。簡單來說,凡是「溯及既往」的事,就需要用到變數。

如果此時老師問我「上次的數學考幾分?」,我回答80分,為什麼我能夠回答呢?因為之前發數學考卷的時候,我有把分數記下來;如果數學考卷發下來我卻沒有記得分數,那麼此時我就沒有辦法回答老師。同樣的,我如果要電腦給我之前某時刻的某資料,當然就必須在那個「某時刻」命令電腦把它記憶下來,而記憶的方式就是用變數。不過人和電腦有一點點不同--人會把所有事記下來,久了就忘掉;電腦只記我命令它記的東西,但是永遠不會忘掉。

此外,變數有分類型,如整數、實數、部隊、…,這就好像人的記憶有文字、圖像、聲音、…一樣。我們不能把文字當成圖片來記,除非先把文字轉成圖片。同樣的,如果我想讓電腦用整數的方式把實數記下來,就得先把實數轉成整數,才能儲存到整數類型的變數中,像這樣: Set N = Integer(3.8)。不過這樣一來,電腦存的是3而不是3.8,小數點的部分就遺失了。這好像我們如果把文字用圖片的方式記憶,或者用言語描述一個景象(圖片轉成聲音),就 會有失真的現象。

什麼時候要使用變數呢?基本上這是一種經驗,大家多看演示,多思考就知道了。

變數常常用在需要一個地方暫放資料的時候。例如我要交換A、B兩部隊的hp,我如果直接把A的hp改成B的hp,那要怎麼把B的hp改成A之前的呢?這已經讀取不到了。所以我建立一個變數X,先設定X = A的hp,然後設定A的hp = B的hp,最後是B的hp = X,如此一來就能順利完成了。在此例中,變數X代表A「之前的」hp。

有時單一功能不得已要分成多個觸發製作,例如擊退技能就是好例子,第一個觸發由施法啟動,然後開啟第二個觸發每0.0x秒移動目標使其後退。第二個觸發的事件和施法完全無關,此時要抓取施展目標是徒勞的,然而第一個觸發和施法有關,所以我就得趁著抓的到施法目標時,將其用變數紀錄,下一個觸發則從變數讀取。此例中,變數代表第二個觸發「之前」執行的第一個觸發的事件回應值。

變數也用來記錄一個會隨時間不斷變動的量。假設在一個單機遊戲中,我想設定「當玩者英雄死亡時,殺死他的電腦玩者得到他生前殺人數50倍的賞金」,那麼要怎麼取英雄生前的殺人數呢?我可以設定一個記錄殺人數的變數叫做CountKills,然後建立一個觸發「當部隊死亡,且殺人者為玩者的英雄,則設定CountKills為CountKills+1」。接著我就再寫一個觸發:「當玩者英雄死亡時,給予殺人者50 x CountKills的黃金,並設定CountKills為0」。本例中,變數CountKills代表玩者英雄「之前的」殺人總數。

有時我們事件會寫「Unit - Archmage 0000 <gen> Dies」,那個Archmage 0000 <gen>是代表我在地圖上放置的大法師。事實上,由於我在觸發中使用到它,電腦會在地圖初始化的時候為它建立一個變數,以便我在遊戲中能夠讀取並操作那個部隊,標記<gen>就表示那是一個初始化時設定好的變數。

Last created Unit、Last created special effect、…也是變數。當我用觸發創造部隊時,B社內部的函數會創造一個部隊,並且把它存到Last created Unit,以便我接下來對它進行操作。如果我創造了一個步兵,Last created Unit指的是那個步兵,我再創造一個火槍兵,這時Last created Unit指的是那個火槍兵,此時我就無法對步兵操作了,除非我在創造步兵之後先用一個變數記下來: Set xxx = Last created Unit,再創造火槍兵。

陣列(Array)

如果說變數是已被使用並貼上標籤的櫃子,那麼陣列就是被貼上標籤且編號的一整組櫃子。其中陣列名稱就是櫃子組的名稱,陣列索引值就是櫃子組中的櫃子編號,陣列的值就是櫃子中存放的東西。所以:
定義變數XXX,就好像在一個大房間裡,找一大群沒有標籤的櫃子,貼上寫著「XXX」的標籤。(如果已經有個叫「XXX」的變數存在, 我就不能再定義它。一般在這種情形下程式會出錯)
設定XXX[OOO]變數的值,就好像去找貼著「XXX」標籤的櫃子組中的第OOO個櫃子,把東西存放進去。
取出XXX[OOO]變數的值,就好像去找貼著「XXX」標籤的櫃子中的第OOO個櫃子,把裡面的東西拿出來用。(不過電腦的世界和現實世界不太一樣,電腦拿完東西使用以後,東西不會消失,也就是說,讀取變數後,那個櫃子裡的東西仍然存在。)
修改XXX[OOO]變數的值,就好像去找貼著「XXX」標籤的櫃子中的第OOO個櫃子,把裡面的東西拿出來丟掉,再放一個新的東西進去。

承前面的例子,如果我想設定「當玩者英雄死亡時,殺死他的玩者得到他生前殺人數50倍的賞金」,但是這次是多人遊戲,裡面的12個玩家都有一個英雄,難道我們要用12個變數分別記錄?這時陣列的好用就出來了,我們可以寫一個觸發:「當部隊死亡,且殺人者是英雄,則設定CountKills[殺人者的玩者編號]為CountKills[殺人者的玩者編號]+1」(也就是如果玩者1殺人,則CountKills[1]計數加1;若玩者2殺,則CountKills[2]計數加1……),再寫一個觸發:「當一個英雄死亡時,給予殺人者50 x CountKills[死亡者的玩者編號]的黃金,並設定CountKills[死亡者的玩者編號]為0」,輕鬆解決這個問題。

陣列也很常配合迴圈和隨機數使用。我可以在初始化時用陣列作表格,然後在遊戲中用迴圈來控制表格中的所有元件,或者用隨機數抽取表格中的任意一個。如果我想製作「每經過30秒,就在主堡隨機產生N個步兵、火槍兵、騎士、或法師」,可以先建立一個部隊類型的陣列UnitTypeList[],並且在初始化時,分別設定UnitTypeList[1]=步兵、UnitTypeList[2]=火槍兵、UnitTypeList[3]=騎士、UnitTypeList[4]=法師、…。然後就能寫「每經過30秒,在主堡產生N個UnitTypeList[Random integer number between 1 and 4]」;如果我要它輪流產生,可以寫「每經過30秒,設定i = i mod 4 + 1,在主堡產生N個UnitTypeList[i]」;如果我要每30秒4種都出,可以用迴圈:「每經過30秒,for Integer A = 1 to 4,在主堡產生N個UnitTypeList[Integer A]」。上例中UnitTypeList[]就像是一個表格, 我可以抽取其中一個、其中幾個,或者其中全部:

編號 0 1 2 3 4 5
資料 (空) 步兵 火槍兵 騎士 法師 (空)

魔獸的陣列是從0開始(一般程式都會從0開始,不過人的習慣一般從1開始),8191結束,即xxx[0~8191],總共8192個。

For迴圈

迴圈是一種讓電腦連續執行一段程式碼多次的功能,可分為一般程式都有的For迴圈,以及B社特別設計的Pick迴圈。 先看For迴圈,假設我們寫入以下的觸發:

Loop Test
 Events
  Player - Player 1 (Red) types a chat message containing -test as An exact match
 Conditions
 Actions
  Visibility - Disable fog of war
  For each (Integer A) from 1 to 3, do (Actions)
   Loop - Actions
    Game - Display to (All players) the text: (String((Integer A)))

  Visibility - Disable black mask

這段觸發會被轉成JASS碼儲存和執行,如下:

function Trig_Loop_Test_Actions takes nothing returns nothing
 call FogEnableOff( )
 set bj_forLoopAIndex = 1 ---------------------------------------------設定變數IndexA為1
 set bj_forLoopAIndexEnd = 3 ------------------------------------------設定變數IndexAEnd為3
 loop -----------------------------------------------------------------進入迴圈
  exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd --------------------判斷當IndexA>IndexAEnd就跳出迴圈
  call DisplayTextToForce( GetPlayersAll(), I2S(GetForLoopIndexA()) )
  set bj_forLoopAIndex = bj_forLoopAIndex + 1
------------------------設定IndexA的值加1
 endloop --------------------------------------------------------------迴圈結束(執行至此會再回到loop)
 call FogMaskEnableOff( )
endfunction

//===========================================================================
function InitTrig_Loop_Test takes nothing returns nothing
 set gg_trg_Loop_Test = CreateTrigger( )
 call TriggerRegisterPlayerChatEvent( gg_trg_Loop_Test, Player(0), "-test", true )
 call TriggerAddAction( gg_trg_Loop_Test, function Trig_Loop_Test_Actions )
endfunction

它的用途就是重複執行迴圈內的敍述,可以用很短的文字敍述,執行很多遍類似的動作。以此範例來說,它會依序印出1,2,3。如果我把它改成For each (Integer A) from 1 to 100, …,那麼就會印出1,2,3,…,100

Pick迴圈

Pick迴圈是b社用一些不可思議的方法寫出來的迴圈型式(原理?筆者也不知道=.=")。它可以對一 群部隊、玩家、可毀物中的所有對象做類似的操作。讓我們看看範例:  

Pick Test
 Events
  Player - Player 1 (Red) types a chat message containing -test as An exact match
 Conditions
 Actions
  Visibility - Disable fog of war
  Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
   Loop - Actions
    Unit - Kill (Picked unit)

  Visibility - Disable black mask

同樣地,它也會被轉成JASS碼,如下:

function Trig_Pick_Test_Func002A takes nothing returns nothing
 call KillUnit( GetEnumUnit() )
endfunction

function Trig_Pick_Test_Actions takes nothing returns nothing
 call FogEnableOff( )
 call ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect()), function Trig_Pick_Test_Func002A )
 call FogMaskEnableOff( ) └──將Unit Group內的部隊選取,執行一段程式碼(Trig_Pick_Test_Func002A)
endfunction

//===========================================================================
function InitTrig_Pick_Test takes nothing returns nothing
 set gg_trg_Pick_Test = CreateTrigger( )
 call TriggerRegisterPlayerChatEvent( gg_trg_Pick_Test, Player(0), &quot;-test&quot;, true )
 call TriggerAddAction( gg_trg_Pick_Test, function Trig_Pick_Test_Actions )
endfunction

假設全地圖有三個部隊,分別叫a,b,c。它的執行順序如下:

function Trig_Pick_Test_Func002A takes nothing returns nothing
 call KillUnit( GetEnumUnit() ) ---(3) ---(4) ---(5)
endfunction

function Trig_Pick_Test_Actions takes nothing returns nothing
 call FogEnableOff( ) ---(1)
 call ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect()), function Trig_Pick_Test_Func002A ) ---(2)
 call FogMaskEnableOff( ) ---(6)
endfunction ---(7)

//===========================================================================
function InitTrig_Pick_Test takes nothing returns nothing
 set gg_trg_Pick_Test = CreateTrigger( )
 call TriggerRegisterPlayerChatEvent( gg_trg_Pick_Test, Player(0), &quot;-test&quot;, true )
 call TriggerAddAction( gg_trg_Pick_Test, function Trig_Pick_Test_Actions )
endfunction

執行後結果很簡單,就是殺掉a,b,c三個部隊。

中斷(Skip Remaining Actions)

一般情況下,當程式執行到Skip Remaining Actions那一行時,會跳出目前正在執行的函式。如下:

Return Test
 Events
  Time - Elapsed game time is 5.00 seconds
 Conditions
 Actions
  Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees ---(1)
  Skip remaining actions ---(2) --------------------跳出整個Actions
  Unit - Create 1 Rifleman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees

轉成JASS則為:

function Trig_Return_Test_Actions takes nothing returns nothing
 call CreateNUnitsAtLoc( 1, 'hfoo', Player(0), GetRectCenter(GetPlayableMapRect()), bj_UNIT_FACING )
---(1)
 return ---(2) ------------------------跳出整個函數(Trig_Return_Test_Actions)
 call CreateNUnitsAtLoc( 1, 'hrif', Player(0), GetRectCenter(GetPlayableMapRect()), bj_UNIT_FACING )
endfunction

//===========================================================================
function InitTrig_Return_Test takes nothing returns nothing
 set gg_trg_Return_Test = CreateTrigger( )
 call TriggerRegisterTimerEventSingle( gg_trg_Return_Test, 5 )
 call TriggerAddAction( gg_trg_Return_Test, function Trig_Return_Test_Actions )
endfunction

綜合教學/觸發器使用教學/3.基本概念.txt · 上一次變更: 2007年11月12日 9:26 pm 來自 wasabi
www.chimeric.de Creative Commons License Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0