LV. 42
GP 1k

 ~輕鬆學JASS~ (應用篇)

樓主 Weber Weberkkk

===============

  ---(應用篇)---

===============


《10》共用觸發製做

  function可以導入各種引數進行處理,而共用觸發,就是把一些常用的function片段集合起來,方便其他觸發呼叫,上面的範例也有些類似的東西,但實用性還不夠,下面貼一段更實用的觸發來解釋所謂的共用觸發:


//施加傷害
function DamageSE_D takes nothing returns nothing

  call UnitDamageTarget(udg_Z_GcUni[1], GetEnumUnit(), udg_Z_GcInt[1], true, false, ATTACK_TYPE_NORMAL, udg_Z_GcDam[1], WEAPON_TYPE_WHOKNOWS)
endfunction


//辨識敵我、排除已死亡單位、排除建築、排除魔免單位
function DamageSE_AI0 takes nothing returns boolean
local unit U = GetFilterUnit()

  if (IsPlayerEnemy(GetOwningPlayer(U), GetOwningPlayer(udg_Z_GcUni[1])) == true) and ( GetUnitState(U, UNIT_STATE_LIFE) > 0 ) and ( IsUnitType(U, UNIT_TYPE_STRUCTURE) == false ) and ( IsUnitType(U, UNIT_TYPE_MAGIC_IMMUNE) == false ) and (IsUnitInRangeLoc(U,udg_Z_GcLoc[1],udg_Z_GcRea[1])) then
    set U = null
    return true
  endif
  set U = null
  return false
endfunction


//辨識敵我、排除已死亡單位、排除建築
function DamageSE_AI1 takes nothing returns boolean
local unit U = GetFilterUnit()

  if (IsPlayerEnemy(GetOwningPlayer(U), GetOwningPlayer(udg_Z_GcUni[1])) == true) and ( GetUnitState(U, UNIT_STATE_LIFE) > 0 ) and ( IsUnitType(U, UNIT_TYPE_STRUCTURE) == false ) and (IsUnitInRangeLoc(U,udg_Z_GcLoc[1],udg_Z_GcRea[1])) then
    set U = null
    return true
  endif
  set U = null
  return false
endfunction

 

//======================================
//  主觸發
//======================================

//Unit傷害者、Location傷害地點、real傷害範圍、group排除群組、integer傷害值、integer傷害類型、string附著點、string特效

function DamageSE takes unit U ,location P ,real Range ,group NotG ,integer Damage ,integer DamageType ,string SEP ,string SE returns nothing
local group G = CreateGroup()
local boolexpr Con

  if SEP == "P" then      //特效點設P為對傷害地點
    call DestroyEffect(AddSpecialEffectLoc( SE, P ))
  elseif SE != null then     //否則產生特效於傷害者上
    call DestroyEffect(AddSpecialEffectTarget( SE, U, SEP ))
  endif


set udg_Z_GcUni[1] = U
set udg_Z_GcInt[1] = Damage
set udg_Z_GcLoc[1] = P
set udg_Z_GcRea[1] = Range

  if DamageType == 0 then
    set udg_Z_GcDam[1] = DAMAGE_TYPE_MAGIC  //傷害類型0=魔法
    set Con = Condition(function DamageSE_AI0)  //設定Con不可攻擊魔免單位

  elseif DamageType == 1 then
    set udg_Z_GcDam[1] = DAMAGE_TYPE_UNKNOWN  //傷害類型1=未知
    set Con = Condition(function DamageSE_AI1)  //設定Con可攻擊魔免單位
  endif

  
  call GroupEnumUnitsInRange(G,GetLocationX(P),GetLocationY(P),(Range+50),Con) //挑取單位並使用Con判斷

  if NotG != null then
    call GroupRemoveGroup(NotG,G)
  endif

  call ForGroup(G,function DamageSE_D)
  call DestroyGroup(G)
  call DestroyBoolExpr(Con)
  set U = null
  set G = null
  set Con = null
endfunction


傷害區域內的部隊,是很常用的功能
內建的傷害區域部隊無法辨識敵我

因此我們可以創造一個共用觸發,負責傷害區域內的部隊


以這個觸發為例,它有兩個filter可以使用
可以視需求來挑取不同的單位,也可以另外新增其他的filter

先挑取範圍+50的部隊
再使用filter內的IsUnitInRangeLoc來準確的判斷部隊是否在圓區域內


完成這個共用觸發之後
假如我想要對範圍300內敵方非魔免部隊造成250點傷害
並播放一個特效在傷害地點

我只要這樣寫:

  call DamageSE(Unit,Loc,300,null,250,0,"P","特效名稱")


是不是比每次都重寫一樣的東西要輕鬆許多呢?

當某段程式碼會被大量使用的時候,請把它製做成共用觸發吧!

 

《11》回傳錯誤應用

  WE自學手冊對於回傳錯誤的介紹非常詳盡,概括了所有細節,所以這邊只講實際運用的部分,handle是所有物件的父類型,底下包含觸發器、部隊、群組、地點、特效、計時器等等各種雜物,每個handle被創造之後,都會由程式賦予一組ID用來調閱,這個ID是絕不重複,獨一無二的,當我們用變數紀錄unit或locatoin等物件的時候,實際上只保存了整數型態的物件ID

  我們可以利用回傳錯誤來取得handle的ID,或是輸入ID來取得unit、timer等子類型的物件,這個功能或許沒甚麼用處,但是當回傳錯誤搭配GameCache的時候,它的實用價值就相當高了,GameCache可以開設資料夾,並保存部隊、實數、整數、布林、字串等資料,所以我們可以做出一系列的函數:


function H2I takes handle h returns integer
  return h
  return 0
endfunction

function H2S takes handle h returns string
  return I2S(H2I(h))
endfunction

function SaveHandleHandle takes string HandleID, string name, handle value returns nothing
  if ( value == null ) then
    call FlushStoredInteger(GameCache(), HandleID, name)
  else
    call StoreInteger(GameCache(), HandleID, name, H2I(value))
  endif
endfunction

function GetHandleUnit takes string HandleID, string name returns unit
  return GetStoredInteger(GameCache(), HandleID, name)
  return null
endfunction

unction GetHandleTrigger takes string HandleID, string name returns trigger
  return GetStoredInteger(GameCache(), HandleID, name)
  return null
endfunction

unction GetHandleTimer takes string HandleID, string name returns timer
  return GetStoredInteger(GameCache(), HandleID, name)
  return null
endfunction

--(其他略,寫法差不多都是這樣...)--


  我們可以用物件的ID做為資料夾名稱,並存入我們需要的資料,將資料命名為特定的檔名,因為物件的ID不會改變,所以這些資料等於是綁定在物件身上,假設我們抓到了部隊A,我們可以用部隊A的ID在GameCache裡面開設資料夾
並存入我們需要記錄的資料。

  當部隊A再度觸動其他事件的時候,我們也可以利用部隊A的ID,把當時存入的資料讀取出來,這方法被廣泛的應用在AUD系統,用來清理部隊死亡後的AUD觸發器,另外一種比較常見的方法是使用計時器的ID做為資料夾名稱,用來在TimerStart的時候,靈活的讀取需要的變數或物件資訊。

  回傳錯誤是個將handle與integer互相轉換的系統,只要搭配GameCache就能保存任何需要的資料,因為ID不會重複,所以也不需要擔心變數衝突的問題,但因為需經過幾道轉換手續,所以回傳錯誤的效率仍比全域變數差一些,目前VJass有功能可以使用全域變數達到類似的效果,有興趣的玩家可以查閱相關資訊。


《12》回傳錯誤之CP怪重生系統範例


//================================
//         把怪物資料紀錄在GameCache
//================================

function CR_SaveLocation takes nothing returns nothing
local integer Index = GetHandleInteger("CRI","Index")
local unit U = GetEnumUnit()
local string S = "CRR" + I2S(Index)     //以Index為名稱開設資料夾儲存

if U != null then
  
call SaveHandleInteger("CRI","Index",(Index+1))

  call SaveHandleReal(S,"X",GetUnitX(U))      //位置X
  call SaveHandleReal(S,"Y",GetUnitY(U))      //位置Y
  call SaveHandleReal(S,"Ang",GetUnitFacing(U))  //面向角
  call SaveHandleInteger(S,"D",GetUnitTypeId(U))  //部隊類型

  call SaveHandleString(("CRU" + H2S(U)),"S",S) //將Index紀錄在部隊ID的資料夾內
endif
  
  set U = null
endfunction


//================================
//   選取所有CP怪,並執行紀錄位置的Function
//================================

function CR_PickAllCreep takes nothing returns boolean
local group G = CreateGroup()
  call GroupEnumUnitsOfPlayer(G, Player(12), null)

  call SaveHandleInteger("CRI","Index",0)
  call ForGroup(G,function CR_SaveLocation)
  call DestroyGroup(G)
  call DestroyTrigger(GetTriggeringTrigger())
  call FlushHandleLocals("CRI")      //刪!
  
  set G = null
  return false
endfunction


function InitTrig_Set_Creep_Revive takes nothing returns nothing
  set gg_trg_Set_Creep_Revive = CreateTrigger()
  call TriggerAddCondition( gg_trg_Set_Creep_Revive,Condition(function CR_PickAllCreep))
endfunction

以上函數在地圖初始化的時候執行

這個回傳錯誤是先用"CRR" + I2S(Index)字串開設資料夾名稱
儲存怪物的資料

再把"CRR" + I2S(Index)字串紀錄在部隊ID的資料夾內

之後只要偵測到部隊死亡,就可以抓到部隊ID並提取"CRR" + I2S(Index)字串
用來讀取一開始存入的資料

當然也可以不用這麼麻煩,直接用H2S把怪物ID拿來當作資料夾名稱存資料也可以
不過這範例沒這樣做,是因為每隻怪物的ID都不重複
直接用H2S把怪物ID拿來當作資料,會多次刪改資料,造成不必要的資源耗損
也可能衍生出CP怪物位置錯亂的BUG

所以採用儲存主要資料在固定的資料夾
並儲存關鍵的字串在怪物身上的方式,來減少各種可能發生的問題


//================================
//         以計時器啟動的復活Function
//================================

function CR_CreepRevive takes nothing returns nothing
local timer T = GetExpiredTimer()
local string S = GetHandleString(("CRT" + H2S(T)),"S")
local location P = Location(GetHandleReal(S,"X"),GetHandleReal(S,"Y"))
local unit U = CreateUnitAtLoc(Player(12),GetHandleInteger(S,"D"),P,GetHandleReal(S,"Ang"))

  call RemoveLocation(P)
  call DestroyTimer(T)                  //計時器沒用了,刪!
  call FlushHandleLocals(("CRT" + H2S(T)))    //計時器資料夾,刪!
   call SaveHandleString(("CRU" + H2S(U)),"S",S) //將Index紀錄在新部隊ID的資料夾內

  set T = null
  set U = null
  set P = null
endfunction

 

//================================
//       Creep死的時候創造計時器,並紀錄怪物ID
//================================

function CR_CreepDie takes unit U returns boolean
local timer T = CreateTimer()
local string S = GetHandleString(("CRU" + H2S(U)),"S")

  call FlushHandleLocals(("CRU" + H2S(U)))    //舊部隊資料夾,刪!
  call SaveHandleString(("CRT" + H2S(T)),"S",S)     //將部隊ID紀錄在計時器ID的資料夾內

  call TimerStart( T, 20.00, false, function CR_CreepRevive )

  set T = null
  set U = null
  return false
endfunction

 

function InitTrig_Creep_Revive takes nothing returns nothing
  set gg_trg_Creep_Revive = CreateTrigger( )
  call TriggerRegisterAnyUnitEventBJ( gg_trg_Creep_Revive, EVENT_PLAYER_UNIT_DEATH )
  call TriggerAddCondition( gg_trg_Creep_Revive, Condition( function CR_CreepDie ) )
endfunction


這是用來偵測部隊死亡的觸發器
部隊死後先把資料紀錄在計時器上面

以免部隊被移除之後,會提取不到該有的資料
等Timer時間到之後,再把資料從Timer上面抓出來

拿到關鍵字之後,就開始從GameCache提取需要的資料
XY做標的Real、初始的面向角、部隊類型等

若用變數儲存資料,也能達到類似的效果
但相對於回傳錯誤的應用,採用變數陣列會讓整個觸發更複雜


回傳錯誤在本範例裡面扮演「紀錄關鍵字」的角色

部隊本身就是紀錄資訊的鑰匙
只要偵測到部隊死亡,就能領取我們存入的資訊!

--<常用回傳錯誤列表>--

//======================================
//  回傳錯誤
//======================================

function H2I takes handle h returns integer
    return h
    return 0
endfunction

function H2S takes handle h returns string
    return I2S(H2I(h))
endfunction

function I2T takes integer h returns trigger
    return h
    return null
endfunction

function I2TA takes integer h returns triggeraction
    return h
    return null
endfunction

function I2U takes integer h returns unit
    return h
    return null
endfunction

function I2G takes integer h returns group
    return h
    return null
endfunction

function I2CT takes integer h returns timer
    return h
    return null
endfunction

function I2P takes integer h returns player
    return h
    return null
endfunction

function I2L takes integer h returns lightning
    return h
    return null
endfunction

function I2B takes integer h returns boolean
    if ( h>0 ) then
        return true
    endif
    return false
endfunction

function I2E takes integer h returns effect
    return h
    return null
endfunction

function B2I takes boolean b returns integer
    if b then
        return 1
    endif
    return 0
endfunction

function C2I takes code C returns integer
    return C
    return 0
endfunction

 

 

 

//======================================
//  儲存變數
//======================================

function GameCache takes nothing returns gamecache
    return udg_Z_Gc
endfunction


function SaveHandleHandle takes string HandleID, string name, handle value returns nothing
    if ( value == null ) then
        call FlushStoredInteger(GameCache(), HandleID, name)
    else
        call StoreInteger(GameCache(), HandleID, name, H2I(value))
    endif
endfunction

function SaveHandleInteger takes string HandleID, string name, integer value returns integer
    call StoreInteger(GameCache(), HandleID, name, value)
    return value
endfunction

function SaveHandleReal takes string HandleID, string name, real value returns nothing
    call StoreReal( GameCache(), HandleID, name, value)
endfunction

function SaveHandleBoolean takes string HandleID, string name, boolean value returns nothing
    call StoreBoolean( GameCache(), HandleID, name, value)
endfunction

function SaveHandleString takes string HandleID, string name, string value returns nothing
    call StoreString( GameCache(), HandleID, name, value)
endfunction

function SaveStringHandle takes string title, string name, handle value returns nothing
    call StoreInteger( GameCache(), title, name, H2I(value) )
endfunction

function SaveStringInteger takes string title, string name, integer value returns integer
    call StoreInteger(GameCache(), title , name, value)
    return value
endfunction


//======================================
//  刪除變數
//======================================

function FlushHandleInteger takes string HandleID, string name returns nothing
    call FlushStoredInteger(GameCache(), HandleID, name)
endfunction

function FlushHandleReal takes string HandleID, string name returns nothing
    call FlushStoredReal(GameCache(), HandleID, name)
endfunction

function FlushHandleLocals takes string HandleID returns nothing
    call FlushStoredMission(GameCache(), HandleID )
endfunction

 

//======================================
//  讀取變數
//======================================

function GetHandleInteger takes string HandleID, string name returns integer
    return GetStoredInteger(GameCache(), HandleID, name)
endfunction

function GetHandleReal takes string HandleID, string name returns real
    return GetStoredReal(GameCache(), HandleID, name)
endfunction

function GetHandleBoolean takes string HandleID, string name returns boolean
    return GetStoredBoolean(GameCache(), HandleID, name)
endfunction

function GetHandleString takes string HandleID, string name returns string
    return GetStoredString(GameCache(), HandleID, name)
endfunction

function GetHandleLight takes string HandleID, string name returns lightning
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandleTrigger takes string HandleID, string name returns trigger
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandleTrgAct takes string HandleID, string name returns triggeraction
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandleCon takes string HandleID, string name returns conditionfunc
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandleTrgCon takes string HandleID, string name returns triggercondition
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandleTimer takes string HandleID, string name returns timer
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandleTimerDlg takes string HandleID, string name returns timerdialog
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandleUnit takes string HandleID, string name returns unit
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandleRect takes string HandleID, string name returns rect
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandlePlayer takes string HandleID, string name returns player
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

function GetHandleGroup takes string HandleID, string name returns group
    return GetStoredInteger(GameCache(), HandleID, name)
    return null
endfunction

 

function GetStringInteger takes string title, string name returns integer
    return GetStoredInteger(GameCache(), title, name)
endfunction

function GetStringBoolean takes string title, string name returns boolean
    return GetStoredBoolean(GameCache(), title, name)
endfunction


//======================================
//  特殊指令
//======================================


function SetUnitXY takes unit U ,location P returns nothing

    call SetUnitX(U,GetLocationX(P))
    call SetUnitY(U,GetLocationY(P))

endfunction

 


function KillAndRemove takes nothing returns nothing
    call KillUnit(GetEnumUnit())
    call RemoveUnit(GetEnumUnit())
endfunction

 

function TimeKillUnitCore takes nothing returns nothing
local timer T = GetExpiredTimer()
local string S = "TimeKill" + H2S(T)
local unit U = GetHandleUnit(S, "KillUnit")

    call KillUnit(U)
    call RemoveUnit(U)
    call FlushHandleLocals(S)
    call DestroyTimer(T)
    set U = null
    set T = null
endfunction


function TimeKillUnit takes unit U ,real Time returns nothing
local timer T = CreateTimer()
local string S = "TimeKill" + H2S(T)

    call SaveHandleHandle(S, "KillUnit", U)
    call TimerStart( T, Time, false, function TimeKillUnitCore )
    set U = null
    set T = null
endfunction


板務人員:

3963 筆精華,10/04 更新
一個月內新增 0
歡迎加入共同維護。


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】