範例/演算法

「演算法」是一個程式用語,意思是「使用特定語言達成特定目的的一種思維方式」。不可否認,WE的觸發的確和程式語言的概念很相似,所以我們必須學習這種思維方式,才能更加容易了解如何把一個想法化成具體的程式語言(觸發)。以下會採用問題&解答的方式來介紹,大家在看到題目時,可以先在腦中構思作法,然後再看參考解答以及其思維方式。當然這裡所提供的解法並非惟一,讀者可以去思考是否有別的更好的方法。

當一個問題有多種可能的寫法時,什麼樣的寫法是好的?基本上我們寫觸發的優化目標有二:一是讓電腦執行有效率,二是讓人容易讀得懂。有時為了效率會犧牲易讀性;有時為了易讀性會犠牲效率(例如全部用JASS寫最有效率,但是為了易讀,連B社的地圖也並非全用JASS)。一個有技巧的人必須能在兩者之中取得平衡點。

下面提供幾個最簡單的範例,一些比較進階的常見問題可以在FAQ找到。

前提與效果

面對一個要用觸發解決的問題,首先應該先思考:前提是什麼?效果是如何? 前提可以看成是要達成效果的前置因素。大致上可以分成幾個層次:

  1. 可用一個事件解決。如「部隊被攻擊」、「遊戲時間30秒時」、「每5秒一次」、……。

  2. 可用事件與條件解決。如「一個英雄被攻擊」、「玩家失去了所有建築」、「部隊施展了黑死爪」、……。

  3. 必須用多個觸發組合去取出實際或接近的前提。如「一個部隊被投射性技能擊中」、「一個部隊受到傷害」、「一個有重生技能的部隊重生」、……。

如果以上幾個做出來的效果不好或者沒辦法做,最後可以考慮用「每X秒執行一次」的觸發去取接近的效果。

範例

  • 每5秒在地圖中央產生二名玩者一的步兵

    顯然這個問題中,事件是「每5秒執行一次」,動作是「在地圖中央產生二名玩者一的步兵」,而條件則不需要,所以我們可以這樣寫:

    Create Footman
     Events
      Time - Every 5.00 seconds of game time
     Conditions
     Actions
      Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees

  • (地圖上的)阿薩斯死亡時,殺人者得100黃金,而被殺者則損失100黃金

    這個問題的事件很簡單,就是「阿薩斯死亡」,而動作是增加100黃金與減少100黃金,可是要加給誰呢?玩者一殺就給玩者一,玩者二殺就給玩者二;玩者一死就扣玩者一、玩者二死就扣玩者二……這樣寫多累啊?

    要解決這個問題,就得用到事件回應的觀念,當事件是「部隊死亡」時,可以用函數「死亡的部隊(Dying Unit)」、「殺人的部隊(Killing Unit)」、「觸發事件的部隊(即死亡的部隊)(Triggering Unit)」來取得相關的資料。慢著,可是我要加錢給玩者,而不是部隊耶!所以我們可以再用一個函數「Ower of <Unit>」來取出殺人者/被殺者的所屬玩家。 等等!動作的指令中,只有「增加玩者金錢」和「設定玩者金錢」而已,找不到「減少玩者金錢」呀!拜託,要動腦,改成負數不就是減少了嗎?

    Arthas Death
     Events
      Unit - Arthas (Evil) 0000 <gen> Dies
     Conditions
     Actions
      Player - Add 100 to (Owner of (Killing unit)) Current gold
      Player - Add -100 to (Owner of (Dying unit)) Current gold

    如果問題簡化成「(地圖上的)阿薩斯死亡時,被殺者則損失100黃金」,可能就會有人這樣寫:

    Arthas Death2(X)
     Events
      Unit - Arthas (Evil) 0000 <gen> Dies
     Conditions
     Actions
      Player - Add -100 to (Triggering player) Current gold
    這樣寫就錯囉,為什麼?因為觸發事件的是部隊,而不是玩者。
    就好像今天小明被打了,你說:「罰罵小明的人站10分鐘」,這不是莫名奇妙,牛頭不對馬嘴嗎?
    同樣的,今天事件是「阿薩斯死亡」,那麼「觸發事件的玩者」自然沒有任何意義。

  • (地圖上的)阿薩斯死亡時,殺人者得100黃金,而被殺者則損失100黃金。但被殺者的金錢不到100時,則把所有被殺者的金錢給殺人者

    這個問題是前一個問題的加強版,顯然我們在面對像前面那個問題時,應該要考慮到此種情況的處理方式。

    喂!別急著看解答,不妨先想想看怎麼做再看範例:

    Arthas Death adv1
     Events
      Unit - Arthas (Evil) 0000 <gen> Dies
     Conditions
     Actions
      Player - Add (Min(((Owner of (Triggering unit)) Current gold), 100)) to (Owner of (Killing unit)) Current gold
      Player - Add ((Min(((Owner of (Triggering unit)) Current gold), 100)) x -1) to (Owner of (Triggering unit)) Current gold

    Arthas Death adv2
     Events
      Unit - Arthas (Evil) 0000 <gen> Dies
     Conditions
     Actions
      Player - Add ((Min(((Owner of (Triggering unit)) Current gold), 100)) x -1) to (Owner of (Triggering unit)) Current gold
      Player - Add (Min(((Owner of (Triggering unit)) Current gold), 100)) to (Owner of (Killing unit)) Current gold

    上面兩個寫法看起來有點高級,是不是,何者比較正確呢?我們可以試著套數字去算:
    adv1:
    若阿薩斯的擁有者有105黃金(>100),則(Min(((Owner of (Triggering unit)) Current gold), 100))是100,所以殺死阿薩斯的玩者得到100黃金。
    接著,(Min(((Owner of (Triggering unit)) Current gold), 100))是100,然後阿薩斯的擁有者損失100黃金。 若阿薩斯的擁有者有90黃金(<100),則(Min(((Owner of (Triggering unit)) Current gold), 100))是90,所以殺死阿薩斯的玩者得到90黃金,
    接著,(Min(((Owner of (Triggering unit)) Current gold), 100))是90,然後阿薩斯的擁有者損失90黃金。

    adv2:
    若阿薩斯的擁有者有105黃金(>100),則(Min(((Owner of (Triggering unit)) Current gold), 100))是100,所以阿薩斯的擁有者損失100黃金。
    接著,(Min(((Owner of (Triggering unit)) Current gold), 100))是5,然後殺死阿薩斯的玩者得到5黃金。
    若阿薩斯的擁有者有105黃金(>100),則(Min(((Owner of (Triggering unit)) Current gold), 100))是90,所以阿薩斯的擁有者損失90黃金。
    接著,(Min(((Owner of (Triggering unit)) Current gold), 100))是0,然後殺死阿薩斯的玩者得到0黃金。

    誰對誰錯很明顯了吧?所以,即使只是一個小小的順序差異都可能導致嚴重問題,要多加小心。

    此外還有幾種寫法,邏輯上都沒有錯,大家可以選一個比較習慣的使用(不過筆者個人比較推薦第3種):

    Arthas Death adv3 (建立一個整數變數N)
     Events
      Unit - Arthas (Evil) 0000 <gen> Dies
     Conditions
     Actions
      Set N = (Min(((Owner of (Triggering unit)) Current gold), 100))
      Player - Add (N x -1) to (Owner of (Triggering unit)) Current gold
      Player - Add N to (Owner of (Killing unit)) Current gold

    Arthas Death adv4
     Events
      Unit - Arthas (Evil) 0000 <gen> Dies
     Conditions
     Actions
      If (All Conditions are True) then do (Then Actions) else do (Else Actions)
       If - Conditions
        ((Owner of (Triggering unit)) Current gold) Greater than or equal to 100
       Then - Actions
        Player - Add 100 to (Owner of (Killing unit)) Current gold
        Player - Add -100 to (Owner of (Triggering unit)) Current gold
       Else - Actions
        Player - Add ((Owner of (Triggering unit)) Current gold) to (Owner of (Killing unit)) Current gold
        Player - Add (((Owner of (Triggering unit)) Current gold) x -1) to (Owner of (Triggering unit)) Current gold

  • 遊戲進行到40秒時,在玩者一的所有兵營旁產生4名步兵與2名火槍兵

    顯然這個問題中,事件是「遊戲40秒時執行」,動作是「在玩者一的所有兵營旁產生4名步兵與2名火槍兵」,而條件則不需要。

    事件方面很簡單,可是動作就有一點複雜了,因為即使你翻遍手冊,也一定找不到「在某玩者的所有兵營旁生部隊」這種指令,所以腦筋就要拐點彎了。首先我們先選取玩者一的所有兵營,然後再對所有選到的部隊(兵營)執行「產生部隊」的指令,至於產生在哪裡呢?「兵營旁」可以Position of <兵營>來取得,因此我們可以這樣寫:

    Create Footman2
     Events
      Time - Elapsed game time is 40.00 seconds
     Conditions
     Actions
      Unit Group - Pick every unit in (Units owned by Player 1 (Red) of type Barracks) and do (Actions)
       Loop - Actions
        Unit - Create 4 Footman for Player 1 (Red) at (Position of (Picked unit)) facing Default building facing degrees
        Unit - Create 2 Rifleman for Player 1 (Red) at (Position of (Picked unit)) facing Default building facing degrees

    這樣OK了嗎?嗯,大致上是可以了,不過……Pick Unit會把死亡的部隊也選出來喔,換句話說,如果玩者一有爆掉的兵營,電腦可能會笨笨地在爆掉的兵營旁邊產生部隊,所以完整的寫法可以這樣寫:

    Create Footman3
     Events
      Time - Elapsed game time is 40.00 seconds
     Conditions
     Actions
      Unit Group - Pick every unit in (Units owned by Player 1 (Red) of type Barracks) and do (Actions)
       Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
         If - Conditions
          ((Picked unit) is alive) Equal to True
         Then - Actions
          Unit - Create 4 Footman for Player 1 (Red) at (Position of (Picked unit)) facing Default building facing degrees
          Unit - Create 3 Rifleman for Player 1 (Red) at (Position of (Picked unit)) facing Default building facing degrees
         Else - Actions

    不過也有別的判斷方式,如:

    Create Footman4
     Events
      Time - Elapsed game time is 40.00 seconds
     Conditions
     Actions
      Unit Group - Pick every unit in (Units owned by Player 1 (Red) matching (((Unit-type of (Matching unit)) Equal to Barracks) and (((Matching unit) is alive) Equal to True))) and do (Actions)
       Loop - Actions
        Unit - Create 4 Footman for Player 1 (Red) at (Position of (Picked unit)) facing Default building facing degrees
        Unit - Create 3 Rifleman for Player 1 (Red) at (Position of (Picked unit)) facing Default building facing degrees
    也不失為一個漂亮方法。

    此外要注意一點,前者的If在Pick下面,所以要用Picked Unit做判斷;後者是在matching下做判斷,所以用Matching Unit。

    此外也有像這樣的寫法:

    Create Footman5
     Events
      Time - Elapsed game time is 40.00 seconds
     Conditions
     Actions
      Unit Group - Pick every unit in (Units in (Playable map area) matching (((Owner of (Matching unit)) Equal to Player 1 (Red)) and (((Unit-type of (Matching unit)) Equal to Barracks) and (((Matching unit) is alive) Equal to True)))) and do (Actions)
       Loop - Actions
        Unit - Create 4 Footman for Player 1 (Red) at (Position of (Picked unit)) facing Default building facing degrees
        Unit - Create 3 Rifleman for Player 1 (Red) at (Position of (Picked unit)) facing Default building facing degrees

  • 遊戲進行到40秒時,在所有玩者的所有兵營旁產生4名步兵與2名火槍兵

    乍看之下這個問題和上面的很類似,只不過我們可以換成Unit Group - Pick every unit in (Units of type Barracks) and do (Actions),可是當你寫到動作時,問題就來了:要為哪個玩者創造部隊?

    這個前面學過,用「選到的玩家的擁有者」就好囉。以下為二種寫法:

    Create Footman6
     Events
      Time - Elapsed game time is 40.00 seconds
     Conditions
     Actions
      Unit Group - Pick every unit in (Units in (Playable map area) matching (((Unit-type of (Matching unit)) Equal to Barracks) and (((Matching unit) is alive) Equal to True))) and do (Actions)
       Loop - Actions
        Unit - Create 4 Footman for (Owner of (Picked unit)) at (Position of (Picked unit)) facing Default building facing degrees
        Unit - Create 3 Rifleman for (Owner of (Picked unit)) at (Position of (Picked unit)) facing Default building facing degrees

    Create Footman7
     Events
      Time - Elapsed game time is 40.00 seconds
     Conditions
     Actions
      Unit Group - Pick every unit in (Units of type Barracks) and do (Actions)
       Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
         If - Conditions
          ((Picked unit) is alive) Equal to True
         Then - Actions
          Unit - Create 4 Footman for (Owner of (Picked unit)) at (Position of (Picked unit)) facing Default building facing degrees
          Unit - Create 3 Rifleman for (Owner of (Picked unit)) at (Position of (Picked unit)) facing Default building facing degrees
         Else - Actions

綜合教學/觸發器使用教學/5.範例和演算法.txt · 上一次變更: 2007年11月12日 9:29 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