簡化JASS碼

判斷條件的精簡化

和之前差不多的例子

TEST
 Conditions
  (Owner of (Triggering unit)) Equal to Player 1 (Red)
  ((Triggering unit) is A Hero) Not equal to True

↓↓↓↓↓↓↓↓轉成JASS

function Trig_TEST_Conditions takes nothing returns boolean
    if ( not ( GetOwningPlayer(GetTriggerUnit()) == Player(0) ) ) then
        return false
    endif
    if ( not ( IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) != true ) ) then
        return false
    endif
    return true
endfunction

可以看到,WE很聰明也很笨,使用這種格式可以很漂亮地把一大串的觸發轉成條理分明的JASS碼,不過也因而產生了不少贅碼。 這一大串的程式碼可以簡化,想想看。反白觀看參考方法:

function Trig_TEST_Conditions takes nothing returns boolean
    return ( GetOwningPlayer(GetTriggerUnit()) == Player(0) ) :return:
        and ( not IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) )
endfunction

不同的例子

TEST
 Conditions
  ((Owner of (Triggering unit)) Equal to Player 1 (Red)) or (((Owner of (Triggering unit)) :return:
   is an ally of Player 1 (Red)) Equal to True)
  ((Triggering unit) is A Hero) Equal to True

↓↓↓↓↓↓↓↓轉成JASS

function Trig_TEST_Func001001 takes nothing returns boolean
    return ( GetOwningPlayer(GetTriggerUnit()) == Player(0) )
endfunction

function Trig_TEST_Func001002 takes nothing returns boolean
    return ( IsPlayerAlly(GetOwningPlayer(GetTriggerUnit()), Player(0)) == true )
endfunction

function Trig_TEST_Conditions takes nothing returns boolean
    if ( not GetBooleanOr( Trig_TEST_Func001001(), Trig_TEST_Func001002() ) ) then
        return false
    endif
    if ( not ( IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true ) ) then
        return false
    endif
    return true
endfunction

又是一大串廢文,怎麼處理它呢?這裡提供幾種方法:

  • 處理方法一:

    function Trig_TEST_Conditions takes nothing returns boolean
        return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) and ( GetOwningPlayer(GetTriggerUnit())==Player(0) 下行接續
            or IsPlayerAlly(GetOwningPlayer(GetTriggerUnit()), Player(0)) ) 
    endfunction
    

     

  • 處理方法二:

    function Trig_TEST_Conditions takes nothing returns boolean
        if not IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) then
            return false
        elseif ( GetOwningPlayer(GetTriggerUnit()) == Player(0) ) then
            return true
        endif
        return IsPlayerAlly(GetOwningPlayer(GetTriggerUnit()), Player(0))
    endfunction
    

     

  • 處理方法三:

    function Trig_TEST_Conditions takes nothing returns boolean
        local boolean c1 = IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO)
        local boolean c2 = ( GetOwningPlayer(GetTriggerUnit()) == Player(0) )
        local boolean c3 = IsPlayerAlly(GetOwningPlayer(GetTriggerUnit()), Player(0))
        return c1 and (c2 or c3)
    endfunction
    

     

法一是最直接的寫法,長度短的話,理所當然應該這麼寫。但是長度如果很長,所有條件擠在同一行,閱讀起來很不方便。 法二可以把內容分成多行,但是其中的邏輯關係需要花一些時間去想、去排列,而且行數往往會變得很多。 法三就排版而言,實在是非常漂亮,不過效率較差。怎麼說呢?

假設IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO)結果為假,我們都知道根據and判斷的原則,只要有一個為假就必然傳回假,電腦也如此偷懶,當它發現第一個項目為假,就直接傳回家,後面那一串根本不理;除非第一項為真,它才會去判斷後續的項目。因此,法一和法二判斷過IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO)以後就傳回false了,後面幾個項目不 必處理;而法三則會先處理所有項目,最後才傳回值,所以法三的效率較差。

法三帶來的排版便利不小,以一般的判斷條件而言,效率的損失非常非常小,小到可以忽略。不過--如果c2、c3用的是自製的判斷函數就難說了,我們以後可能會製作一些極端複雜的判斷函數,這時用法一或法二就能有效減少資源的浪費。

動作的精簡化

範例一

Compound Curse
 Events
  Unit - A unit Starts the effect of an ability
 Conditions
  (Ability being cast) Equal to 融合詛咒
 Actions
  Set TempUnit = (Target unit of ability being cast)
  Set P1 = (Position of (Triggering unit))
  Unit - Create 1 暫時施法者 for (Owner of (Triggering unit)) at :return:
   (Position of (Triggering unit)) facing Default building facing degrees
  Custom script:  call RemoveLocation(udg_P1)
  Unit - Hide (Last created unit)
  Unit - Make (Last created unit) face TempUnit over 0.00 seconds
  -------- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --------
  Unit - Add 融合詛咒-效果1 to (Last created unit)
  Unit - Add 融合詛咒-效果2 to (Last created unit)
  Unit - Add 融合詛咒-效果3 to (Last created unit)
  Unit - Add 融合詛咒-效果4 to (Last created unit)
  Unit - Order (Last created unit) to Human Sorceress - Slow TempUnit
  Unit - Order (Last created unit) to Night Elf Druid Of The Talon - Faerie Fire TempUnit
  Unit - Order (Last created unit) to Undead Necromancer - Cripple TempUnit
  Unit - Order (Last created unit) to Undead Banshee - Curse TempUnit

↓↓↓↓↓↓↓↓轉成JASS

function Trig_Compound_Curse_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A002' ) ) then
        return false
    endif
    return true
endfunction

function Trig_Compound_Curse_Actions takes nothing returns nothing
    set udg_TempUnit = GetSpellTargetUnit()
    set udg_P1 = GetUnitLoc(GetTriggerUnit())
    call CreateNUnitsAtLoc( 1, 'o000', GetOwningPlayer(GetTriggerUnit()), udg_P1, bj_UNIT_FACING )
    call RemoveLocation(udg_P1)
    call ShowUnitHide( GetLastCreatedUnit() )
    call SetUnitFacingToFaceUnitTimed( GetLastCreatedUnit(), udg_TempUnit, 0 )
    // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    call UnitAddAbilityBJ( 'A003', GetLastCreatedUnit() )
    call UnitAddAbilityBJ( 'A005', GetLastCreatedUnit() )
    call UnitAddAbilityBJ( 'A004', GetLastCreatedUnit() )
    call UnitAddAbilityBJ( 'A006', GetLastCreatedUnit() )
    call IssueTargetOrderBJ( GetLastCreatedUnit(), "slow", udg_TempUnit )
    call IssueTargetOrderBJ( GetLastCreatedUnit(), "faeriefire", udg_TempUnit )
    call IssueTargetOrderBJ( GetLastCreatedUnit(), "cripple", udg_TempUnit )
    call IssueTargetOrderBJ( GetLastCreatedUnit(), "curse", udg_TempUnit )
endfunction

//===========================================================================
function InitTrig_Compound_Curse takes nothing returns nothing
    set gg_trg_Compound_Curse = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Compound_Curse, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Compound_Curse, Condition( function Trig_Compound_Curse_Conditions ) )
    call TriggerAddAction( gg_trg_Compound_Curse, function Trig_Compound_Curse_Actions )
endfunction

有沒有什麼需要簡化?當然有,而且多到數不清:

  1. 先從最基本的開始:

    function Trig_Compound_Curse_Conditions takes nothing returns boolean
        if ( not ( GetSpellAbilityId() == 'A002' ) ) then
            return false
        endif
        return true
    endfunction
    

    ↓↓↓↓↓↓↓↓簡化

    function Trig_Compound_Curse_Conditions takes nothing returns boolean
        return ( GetSpellAbilityId() == 'A002' )
    endfunction
    

     

  2. GetSpellTargetUnit()使用了很多次,所以弄成變數udg_Temp_Unit有其價值。
    不過JASS裡既然可以隨便創造區域變數,不妨改用一個較好看的名稱target,辨識上也較快。最後可以考慮把變數清空,不過即使偷懶不做,影響也不會太大:

    function Trig_Compound_Curse_Actions takes nothing returns nothing
        set udg_TempUnit = GetSpellTargetUnit()
        set udg_P1 = GetUnitLoc(GetTriggerUnit())
        call CreateNUnitsAtLoc( 1, 'o000', GetOwningPlayer(GetTriggerUnit()), udg_P1, 下行接續
            bj_UNIT_FACING )
        call RemoveLocation(udg_P1)
        call ShowUnitHide( GetLastCreatedUnit() )
        call SetUnitFacingToFaceUnitTimed( GetLastCreatedUnit(), udg_TempUnit, 0 )
        // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        call UnitAddAbilityBJ( 'A003', GetLastCreatedUnit() )
        call UnitAddAbilityBJ( 'A005', GetLastCreatedUnit() )
        call UnitAddAbilityBJ( 'A004', GetLastCreatedUnit() )
        call UnitAddAbilityBJ( 'A006', GetLastCreatedUnit() )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "slow", udg_TempUnit )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "faeriefire", udg_TempUnit )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "cripple", udg_TempUnit )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "curse", udg_TempUnit )
    endfunction 
    

    ↓↓↓↓↓↓↓↓

    function Trig_Compound_Curse_Actions takes nothing returns nothing
        local unit target = GetSpellTargetUnit()
        set udg_P1 = GetUnitLoc(GetTriggerUnit())
        call CreateNUnitsAtLoc( 1, 'o000', GetOwningPlayer(GetTriggerUnit()), udg_P1, 下行接續
            bj_UNIT_FACING )
        call RemoveLocation(udg_P1)
        call ShowUnitHide( GetLastCreatedUnit() )
        call SetUnitFacingToFaceUnitTimed( GetLastCreatedUnit(), target, 0 )
        // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        call UnitAddAbilityBJ( 'A003', GetLastCreatedUnit() )
        call UnitAddAbilityBJ( 'A005', GetLastCreatedUnit() )
        call UnitAddAbilityBJ( 'A004', GetLastCreatedUnit() )
        call UnitAddAbilityBJ( 'A006', GetLastCreatedUnit() )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "slow", target )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "faeriefire", target )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "cripple", target )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "curse", target )
        //set target = null
    endfunction 
    

     

  3. set, 使用, remove處理點的方法蠻常見且基本,不過既然只創造一個隱藏部隊,我們大可不使用複雜的CreateNUnitAtLoc函數,而改用common.j中較原始的CreateUnitAtLoc取代。 不過還不止這樣……既然隱藏部隊只是要創造在旁邊,那何不改用以座標傳送的CreateUnit函數?如此一來,點的創造和刪除都可以省去了 。

    使用CreateUnit的話,電腦不會把它記錄在Last Created Unit裡,不過我們只要再設一個變數hiddencaster儲存給以後調用,反倒比以後每次都呼叫GetLastCreatedUnit()來得精簡且快速。

    function Trig_Compound_Curse_Actions takes nothing returns nothing
        local unit target = GetSpellTargetUnit()
        set udg_P1 = GetUnitLoc(GetTriggerUnit())
        call CreateNUnitsAtLoc( 1, 'o000', GetOwningPlayer(GetTriggerUnit()), 下行接續
            udg_P1, bj_UNIT_FACING )
        call RemoveLocation(udg_P1)
        call ShowUnitHide( GetLastCreatedUnit() )
        call SetUnitFacingToFaceUnitTimed( GetLastCreatedUnit(), target, 0 )
        // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        call UnitAddAbilityBJ( 'A003', GetLastCreatedUnit() )
        call UnitAddAbilityBJ( 'A005', GetLastCreatedUnit() )
        call UnitAddAbilityBJ( 'A004', GetLastCreatedUnit() )
        call UnitAddAbilityBJ( 'A006', GetLastCreatedUnit() )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "slow", target )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "faeriefire", target )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "cripple", target )
        call IssueTargetOrderBJ( GetLastCreatedUnit(), "curse", target )
        //set target = null
    endfunction
    

    ↓↓↓↓↓↓↓↓

    function Trig_Compound_Curse_Actions takes nothing returns nothing
        local unit target = GetSpellTargetUnit()
        local unit hiddencaster = CreateUnit( GetOwningPlayer(GetTriggerUnit()), 'o000', 下行接續
            GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), bj_UNIT_FACING )
        call ShowUnitHide( hiddencaster )
        call SetUnitFacingToFaceUnitTimed( hiddencaster, target, 0 )
        // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        call UnitAddAbilityBJ( 'A003', hiddencaster )
        call UnitAddAbilityBJ( 'A005', hiddencaster )
        call UnitAddAbilityBJ( 'A004', hiddencaster )
        call UnitAddAbilityBJ( 'A006', hiddencaster )
        call IssueTargetOrderBJ( hiddencaster, "slow", target )
        call IssueTargetOrderBJ( hiddencaster, "faeriefire", target )
        call IssueTargetOrderBJ( hiddencaster, "cripple", target )
        call IssueTargetOrderBJ( hiddencaster, "curse", target )
        //set target = null
        //set hiddencaster = null
    endfunction
    

    GetTriggerUnit()如果用到很多次,我們可以考慮先存進一個變數 重複利用,因為我們不知道GetTriggerUnit()函數裡面有多少的運算,如果把它存進一個變數caster,呼叫caster理論上會比較快速,當然影響力並不大,可以依個人的喜好決定是否使用。而bj_UNIT_FACING意義也不大,因為之後就會設定面向角度,可以改成隨便一個數字(當然不改也可以)。

    function Trig_Compound_Curse_Actions takes nothing returns nothing
        local unit target = GetSpellTargetUnit()
        local unit hiddencaster = CreateUnit( GetOwningPlayer(GetTriggerUnit()), 下行接續
            'o000', GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), bj_UNIT_FACING )
        call ShowUnitHide( hiddencaster )
        call SetUnitFacingToFaceUnitTimed( hiddencaster, target, 0 )
        // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        call UnitAddAbilityBJ( 'A003', hiddencaster )
        call UnitAddAbilityBJ( 'A005', hiddencaster )
        call UnitAddAbilityBJ( 'A004', hiddencaster )
        call UnitAddAbilityBJ( 'A006', hiddencaster )
        call IssueTargetOrderBJ( hiddencaster, "slow", target )
        call IssueTargetOrderBJ( hiddencaster, "faeriefire", target )
        call IssueTargetOrderBJ( hiddencaster, "cripple", target )
        call IssueTargetOrderBJ( hiddencaster, "curse", target )
        //set target = null
        //set hiddencaster = null
    endfunction 
    

    ↓↓↓↓↓↓↓↓

    function Trig_Compound_Curse_Actions takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local unit target = GetSpellTargetUnit()
        local unit hiddencaster = CreateUnit( GetOwningPlayer(caster), 'o000', 下行接續
            GetUnitX(caster), GetUnitY(caster), 0.0 )
        call ShowUnitHide( hiddencaster )
        call SetUnitFacingToFaceUnitTimed( hiddencaster, target, 0 )
        // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        call UnitAddAbilityBJ( 'A003', hiddencaster )
        call UnitAddAbilityBJ( 'A005', hiddencaster )
        call UnitAddAbilityBJ( 'A004', hiddencaster )
        call UnitAddAbilityBJ( 'A006', hiddencaster )
        call IssueTargetOrderBJ( hiddencaster, "slow", target )
        call IssueTargetOrderBJ( hiddencaster, "faeriefire", target )
        call IssueTargetOrderBJ( hiddencaster, "cripple", target )
        call IssueTargetOrderBJ( hiddencaster, "curse", target )
        //set caster = null
        //set target = null
        //set hiddencaster = null
    endfunction
    

     

  4. 再來是函數的精簡化,一般我們用JASS都會直接調用common.j裡的函數,因為blizzard.j的函數 很多只是為了方便GUI處理,到最後通常還是會呼叫common.j定義的最原始函數。如果我們直接使用common.j的函數,就可以省去這段調用,增加執行效率。 像下面改的三種函數,都只是進行小幅的調換順序或調整函數,根本可以直接改用最原始的函數。

    當然,如果blizzard.j的某個函數複雜度較高(像下面的SetUnitFacingToFaceUnitTimed),直接使用反而能使程式碼較簡潔。 例如以筆者會使用UnitHasBuffBJ( unit, buffid )函數,而不把它改成GetUnitAbilityLevel( unit, buffid ) == 0,後者雖然比較有效率,但是文意的傳達卻顯得拐彎抹角,而且長度也較長。

    不整齊的地方可以利用空格縮排使對齊,這樣會比較好看。而'A003'~'A006'也可以考慮依照數字大小排序,這裡就不做了。

    那行分隔線如果覺得不必要也可以刪掉。

    function Trig_Compound_Curse_Actions takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local unit target = GetSpellTargetUnit()
        local unit hiddencaster = CreateUnit( GetOwningPlayer(caster), 'o000', 下行接續
            GetUnitX(caster), GetUnitY(caster), 0.0 )
        call ShowUnitHide( hiddencaster )
        call SetUnitFacingToFaceUnitTimed( hiddencaster, target, 0 )
        // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        call UnitAddAbilityBJ( 'A003', hiddencaster )
        call UnitAddAbilityBJ( 'A005', hiddencaster )
        call UnitAddAbilityBJ( 'A004', hiddencaster )
        call UnitAddAbilityBJ( 'A006', hiddencaster )
        call IssueTargetOrderBJ( hiddencaster, "slow", target )
        call IssueTargetOrderBJ( hiddencaster, "faeriefire", target )
        call IssueTargetOrderBJ( hiddencaster, "cripple", target )
        call IssueTargetOrderBJ( hiddencaster, "curse", target )
        //set caster = null
        //set target = null
        //set hiddencaster = null
    endfunction
    

    ↓↓↓↓↓↓↓↓

    function Trig_Compound_Curse_Actions takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local unit target = GetSpellTargetUnit()
        local unit hiddencaster = CreateUnit( GetOwningPlayer(caster), 'o000', 下行接續
            GetUnitX(caster), GetUnitY(caster), 0.0 )
        call ShowUnit( hiddencaster, false )
        call SetUnitFacingToFaceUnitTimed( hiddencaster, target, 0 )
        call UnitAddAbility( hiddencaster, 'A003' )
        call UnitAddAbility( hiddencaster, 'A005' )
        call UnitAddAbility( hiddencaster, 'A004' )
        call UnitAddAbility( hiddencaster, 'A006' )
        call IssueTargetOrder( hiddencaster, "slow"      , target )
        call IssueTargetOrder( hiddencaster, "faeriefire", target )
        call IssueTargetOrder( hiddencaster, "cripple"   , target )
        call IssueTargetOrder( hiddencaster, "curse"     , target )
        //set caster = null
        //set target = null
        //set hiddencaster = null
    endfunction 
    

     

範例二

Hammer Storm
 Events
  Unit - A unit Starts the effect of an ability
 Conditions
  (Ability being cast) Equal to 鐵槌風暴
 Actions
  Unit - Create 1 暫時施法者 for (Owner of (Triggering unit)) at :return:
   (Position of (Triggering unit)) facing Default building facing degrees
  Unit - Hide (Last created unit)
  Unit - Add 鐵槌風暴-效果 to (Last created unit)
  Unit Group - Pick every unit in (Units within 225.00 of :return:
   (Target point of ability being cast)) and do (Actions)
   Loop - Actions
    Unit - Make (Last created unit) face (Picked unit) over 0.00 seconds
    Unit - Order (Last created unit) to Human Mountain King - Storm Bolt (Picked unit)

↓↓↓↓↓↓↓↓轉成JASS

function Trig_Hammer_Storm_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A000' ) ) then
        return false
    endif
    return true
endfunction

function Trig_Hammer_Storm_Func004A takes nothing returns nothing
    call SetUnitFacingToFaceUnitTimed( GetLastCreatedUnit(), GetEnumUnit(), 0 )
    call IssueTargetOrderBJ( GetLastCreatedUnit(), "thunderbolt", GetEnumUnit() )
endfunction

function Trig_Hammer_Storm_Actions takes nothing returns nothing
    call CreateNUnitsAtLoc( 1, 'o000', GetOwningPlayer(GetTriggerUnit()), 下行接續
        GetUnitLoc(GetTriggerUnit()), bj_UNIT_FACING )
    call ShowUnitHide( GetLastCreatedUnit() )
    call UnitAddAbilityBJ( 'A001', GetLastCreatedUnit() )
    call ForGroupBJ( GetUnitsInRangeOfLocAll(225.00, GetSpellTargetLoc()), 下行接續
        function Trig_Hammer_Storm_Func004A )
endfunction

//===========================================================================
function InitTrig_Hammer_Storm takes nothing returns nothing
    set gg_trg_Hammer_Storm = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Hammer_Storm, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Hammer_Storm, Condition( function Trig_Hammer_Storm_Conditions ) )
    call TriggerAddAction( gg_trg_Hammer_Storm, function Trig_Hammer_Storm_Actions )
endfunction 

這裡你會看到一個麻煩的現象--在純JASS中,ForGroup(和ForGroupBJ差不多)是不太受歡迎的,通常寫純JASS的人都不這麼使用,因為ForGroup之下的動作會另外開在一個函數裡,如此一來我們定義的區域變數都無法使用,而使用JASS撰寫的一個大理由就是能善用區域變數。以這裡為例,假設我在函數Trig_Hammer_Storm_Actions裡設定:

local unit hiddencaster = CreateUnit( GetOwningPlayer(caster), 'o000', GetUnitX(caster), GetUnitY(caster), 0.0 )

在Trig_Hammer_Storm_Func004A中的:

call IssueTargetOrderBJ( GetLastCreatedUnit(), "thunderbolt", GetEnumUnit() )

我們無法取得暫時施法者,因為前面說過,使用CreateUnit函數不會自動記錄Last Created Unit。

怎麼辦呢?通常JASSer會使用另外一種方式來達到類似ForGroup的效果,其中的重點是FirstOfGroup函數,它可以取出group中的第一個部隊。

由於GetSpellTargetLoc()是唯一可以取得施法目標的函數,沒有GetSpellTargetX()和GetSpellTargetY(),所以這裡不改用取座標的GroupEnumUnitsInRange函數。

以下是改寫後的結果:

function Trig_Hammer_Storm_Conditions takes nothing returns boolean
    return ( GetSpellAbilityId() == 'A000' )
endfunction

function Trig_Hammer_Storm_Actions takes nothing returns nothing
    local location targetloc = GetSpellTargetLoc()
    local unit caster = GetTriggerUnit()
    local unit hc = CreateUnit( GetOwningPlayer(caster), 'o000', GetUnitX(caster), GetUnitY(caster), 0.0 )
    local group g
    local unit u
    call ShowUnitHide( hc )
    call UnitAddAbility( hc, 'A001' )
    set g = CreateGroup()
    call GroupEnumUnitsInRangeOfLoc( g, targetloc, 225.0, null)
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        call GroupRemoveUnit( g, u )
        call SetUnitFacingToFaceUnitTimed( hc, u, 0.0 )
        call IssueTargetOrder( hc, "thunderbolt", u )
    endloop
    call DestroyGroup(g)
    call RemoveLocation(targetloc)
    //set targetloc = null
    //set caster = null
    //set hc = null
    //set g = null
    //set u = null
endfunction

//===========================================================================
function InitTrig_Hammer_Storm takes nothing returns nothing
    set gg_trg_Hammer_Storm = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Hammer_Storm, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Hammer_Storm, Condition( function Trig_Hammer_Storm_Conditions ) )
    call TriggerAddAction( gg_trg_Hammer_Storm, function Trig_Hammer_Storm_Actions )
endfunction

這樣撰寫的結果,執行起來會比較有效率(因為減少了幾層不必要的呼叫),但是看起來篇幅長了不少,不是很好看。 所以大多數的 的情況下都會選擇寫GUI,如果你把它轉成JASS,又不簡化它,豈不是自找麻煩? 事實上,大多數用到ForGroup的觸發,通常都較淺顯,不太有寫純JASS的必要。

綜合教學/jass入門教學/a3.簡化jass.txt · 上一次變更: 2007年11月12日 4:45 am 來自 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