WOW8论坛

 找回密码
 立即注册
搜索
热搜: 地形 技能 Lua
查看: 68|回复: 2

~☆【教程】【jass技能入门教程~Part II】【哈希表详解】~

[复制链接]

管理员

发表于 2018-7-18 14:58:01 | 显示全部楼层 |阅读模式
夜の星 发表于 2012-1-7 21:37:24


笨蛋教程的上一篇,请没看过的童鞋先阅读的说~

另外,本篇教程的部分内容难度较大(>.<后面不小心讲深了点),新入门者请有选择性阅读



☆依然笨蛋的前言~
上一次的教程中,星演示了几个简单的jass技能,相信认真看过的话,对于jass的语法以及jass技能的基本构建都有了一个大体的认识;

同时还略微尝试了下计时器与单位组的使用~

但是如果仅仅是如此,那么我们辛辛苦苦学习jass,可就真的大材小用了的说~
从现在开始,我们将进入jass中最精髓的部分之一,也是T中所没有接触过的:
哈希表(hashtable)

注:哈希表为1.24及以上版本才有的功能,以下版本是无法使用的说~
(在1.24之前,游戏缓存(ganecache)+return bug起到了相同的作用,124之后它们即被哈希表取代,并且return bug在1,24之后,被修复了)

本演示侧重于hashtable,仅仅会顺带提到hashtable与gamecache两种方式的等价代码转换~

☆哈希表的特点与优势~
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

当然这个概念可能过于深奥,我们不必了解那么深入,只需要了解它的功能以及如何使用~(当然有能力的童鞋,推荐去百度寻找详解)


先简单介绍下好了~hashtable就相当于一个存储数据的仓库,其具有容量大以及存储速度稳定的特点~

使用hashtable与GetHandleId函数,能够非常轻易地实现一个技能的多人无冲突使用~



☆先来认识下这货~
首先,我们先来声明一个哈希表对象~
由于哈希表通常起到全局范围内的数据存储以及传递~
所以我们绝大多数情况(和所有基本没区别)都是将其作为一个全局变量来声明几乎没有局部变量的哈希表,只有在某些特殊需求下,才会罕见地出现;如果你明确知道自己创建局部hashtable的目的,并且知道如何妥善掌控,那么是毫无问题的
jass
globals
    hashtable ht=InitHashtable()
//函数InitHashtable,无参数,返回一个新建的哈希表对象
//在向一个哈希表中存入数据之前,必须先通过此函数创建哈希表,否则无效(好比你无法往一个根本不存在的容器中倒水一样的说~)
endglobals


很简单,这样就创建了一个哈希表,你可以在地图中的任何地方(没错,任何地方)访问它~
Tips:
(显式声明globals块(也就是上面)的方式,其实是Vjass才有的功能~如果你的编辑器UI没有这个,请在T的变量管理器中,创建一个哈希表对象,但别忘了加上udg_前缀以及调用InitHashtable函数进行初始化~)

然后我们可以试着,在其中存并且读取一些数据~
jass
function Trig_Init_Actions takes nothing returns nothing
    local integer i=5
    local integer ret//两个整数变量
    call SaveInteger(ht,0,0,i)
    //将整数i,存入哈希表ht的0,0号位置~
    set ret=LoadInteger(ht,0,0)
    //设置ret=从哈希表ht的0,0号位置读取数据~
    call BJDebugMsg(I2S(ret))
    //显示ret的值~
endfunction

//==============================================
function InitTrig_Init takes nothing returns nothing
//触发器的初始化函数~
//“地图初始化”这个事件比较特殊,没有代码,只需在上方勾上那个勾即可的说~
    set gg_trg_Init = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Init, function Trig_Init_Actions )
endfunction

                        |  |
                   |  |    测试结果~
                      \     /
                        \ /
S195Q)Q3KC]WV@${GE5_T.jpg
很好,我们这就完成了一次最简单的读写~输出的结果正确~

下面就再详细介绍一下哈希表的相关函数~



☆笨蛋的函数详解?真的好⑨呢~
接下来简单介绍些哈希表的常用函数~



初始化类:
native InitHashtable takes nothing returns hashtable


数据存入类:
native SaveInteger takes hashtable table, integer parentKey, integer childKey, integer value returns nothing
native SaveUnitHandle takes hashtable table, integer parentKey, integer childKey, unit whichUnit returns boolean

该类函数均有一样的格式:

函数名Save+数据格式(如Integer、Boolean,都是变量格式首字母大写)+(Handle(Real、Boolean、Integer、String以外格式均要加))
如上面SaveInteger即保存整数~SaveUnitHandle即保存单位~

特别注意字符串保存函数:SaveStr 名字比较特立独行,单独记忆即可~
参数列表均为4项
①(hashtable)你需要保存数据的哈希表对象~
②(integer)数据保存的路径主索引(也叫父索引)~
③(integer)子索引,同主索引一同构成完整路径~
④(类型不一)各类你需要存入的数据~
返回值一般无视即可~

该类函数还有:
SaveReal , SaveBoolean,SaveStr,SaveUnitHandle,SaveGroupHandle,SaveForceHandle,SaveEffectHandle 等等共几十条~
如果记不住的话,可以在T中写好,然后转成jass查看的说~

注意!一个相同路径(比如0,0)底下,只能存一个Handle类(除integer,boolean,real,string以外;code不算)的数据!
(更准确点,是integer, real, boolean, string, handle各一个)

SaveInteger(ht,0,0,5)与SaveReal(ht,0,0,3.5)不冲突;

SaveUnitHandle(ht,0,0,......)
SaveGroupHandle(ht,0,0,......)//虽然类型不同,但仍然将上面那条存的单位覆盖的说~


并且不可以存入一个null值~
比如SaveUnitHandle(ht,0,0,null)这条语句实际并没有任何作用;
如果要清空数据请见下方专门函数~


数据读取类:
native LoadInteger takes hashtable table, integer parentKey, integer childKey returns integer
native LoadUnitHandle takes hashtable table, integer parentKey, integer childKey returns unit
还有很多其他的,就不一一列举了,与上面Save系列函数一一对应~

该类函数的格式和Save系列十分相似,Load+数据类型+(Handle)
参数列表与上面相比,只是少了一个数据项而已,毕竟现在我们是要读取,而不是保存,只需要路径即可的说~
该类函数的返回值类型,就是你需要读取的数据类型~

判断类:
HaveSavedBoolean
HaveSavedInteger
HaveSavedStr
HaveSavedReal
HaveSavedHandle
该类函数都是三个参数(哈希表,主索引,子索引),用于判断某个位置是否保存了数据~
返回值为布尔类型~
不过这几个功能并不常用,所以就不过多解释了呢~

注意!不要和HaveStoredXXXXX系列的函数混起来,那个是判断缓存中数据的~


单项数据清空(仅常用):
RemoveSavedBoolean
RemoveSavedInteger
RemoveSavedStr
RemoveSavedReal
RemoveSavedHandle
该类函数,顾名思义,就是清除已经存入表中的某个单项数据(即清空某个主目录+子目录下的一项数据)~
参数列表与上面读取类的函数相对应,都是三项~
不同的仅仅是上面的函数是读取数据,而本类函数将数据抹杀~

凡是一切handle类数据的清除,都使用同一个函数RemoveSavedHandle~

多项数据清空:
native FlushChildHashtable takes hashtable table, integer parentKey returns nothing
字面意思清空子哈希表,实际就是清除相同父目录下的数据~
jass
//以下语句存储的数据如果使用 call FlushChildHashtable( ht, 0 )
call SaveInteger( ht, 0, 0, 999 )//被清除
call SaveInteger( ht, 0, 1, 888 )//被清除
call SaveInteger( ht, 0, 2, 777 )//被清除
call SaveReal( ht, 0, 3, 5.5 )//被清除
call SaveUnitHandle( ht, 0, 4, ...... )//被清除
call SaveBoolean( ht, 1, 0, true )//保留
call SaveGroupHandle(ht, 1, 1, CreateGroup() )//保留


native FlushParentHashtable takes hashtable table returns nothing
这个星就不解释了,参数仅仅一个哈希表,猜都能猜到:血洗表中所有数据,并销毁table这个哈希表本身~
也就是说,下次再使用某hashtable的话,要重新InitHashtable()创建的说~


映射(仅一个):
native StringHash takes string s returns integer

本函数的作用就是将玩家输入的字符串,映射为一串整数(不同字串有着非常巨大的几率不重复,但理论上一定存在两个不同字串映射到同一整数上面的可能性)
以迎合哈希表存储时,需要以整数作为路径的需要;
使得用户能够以字符的形式,表示路径~
jass
call SaveInteger( ht, 0, StringHash("Value"), 999 )


几点注意:
该函数不区分字符大小写: aaa,AAA,aAa被认为相同~
该函数与S2I函数有本质区别~

函数GetHandleId(非常重要):
native GetHandleId takes handle h returns integer

或许看了那么久的教程,人会感觉非常困,但是现在无论如何请打起精神来~
本函数可以说是整个哈希表体系中,最重要的东西之一~

它的作用,就是获取一个句柄类型对象的ID~
你可以理解为,所有单位、单位组、玩家、玩家组、特效、闪电、触发、可破坏物......
它们都属于句柄并且每一个都有自己独一无二(有错,独一无二)的整数编号,即HandleId~

本函数无可替代的作用,就是获取句柄对象的ID~
熟悉1.20的使用者可以简单的将这个函数,认为是和H2I完全一样的等价物~
用法很简单的说~如下:
jass
local unit u=GetTriggerUnit()
local effect e=AddSpecialEffect( ...... )
local integer id_1=GetHandleId( u )
local integer id_2=GetHandleId( e )
//说明一下,GetHandleId函数需求的,是一个handle类的数据
//但是你可以随便放入unit, location, effect之类的类型
//因为它们实际上继承于handle

关于这个函数扮演何种重要角色,将在下面详细解说





回复

使用道具 举报

管理员

 楼主| 发表于 2018-7-18 14:58:42 | 显示全部楼层

☆关于存储顺序~
唔......可以看到我们刚才,是将计时器的HandleId作为存储数据的主路径~

有人可能会说,如果作为子路径可不可以,比如
SaveInteger(ht, 0, id, 999) 这样~

当然这样做本身并无问题,但是并不赞成,会使事情变得麻烦的说~



jass
    local timer t=CreateTimer()
    local integer id=GetHandleId(t)
   
    call SaveInteger(ht,  id,  0,  9)
    call SaveInteger(ht,  id,  1,  12)
    call SaveReal   (ht,  id,  2,  4)
    call SaveBoolean(ht,  id,  3,  true)
    call FlushChildHashtable(ht,id)
    //这样就可以清空上面四条(或更多主路径相同)存储的数据~

    call SaveInteger(ht,  0,  id,  9)
    call SaveInteger(ht,  1,  id,  12)
    call SaveReal   (ht,  2,  id,  4)
    call SaveBoolean(ht,  3,  id,  true)
    call RemoveSavedInteger(ht, 0, id)
    call RemoveSavedInteger(ht, 1, id)
    call RemoveSavedInteger(ht, 2, id)
    call RemoveSavedInteger(ht, 3, id)
    //同样的效果,四个数据也被清除了,但是每条存储都必须单独对应一条清除,非常麻烦~
    //相比主路径相同,这样颠倒后更加不易于管理~
    //“绑定”的思想也不是那么明确了的说~


☆一点小知识喵~
jass
//两点(x0,y0),(x1,y1)间距~
local real dist
set dist=SquareRoot(Pow(x0-x1,2.0)+Pow(y0-y1,2.0))

//两点A(x0,y0),B(x1,y1)间方向~
local real ang
set ang=Atan2(y1-y0, x1-x0)
//注意这里是A到B的方向~
//如果写成
set ang=Atan2(y0-y1, x0-x1)
//就成了B到A的方向的说~

//极坐标位移~
//从起始点(x,y),向a方向位移d距离~
set newx = x + d*Cos(a)
set newy = y + d*Sin(a)

//还有一条喵~使用三角函数时,请注意角度制和弧度制的说~


☆热身喵~
写一个具有延时杀死单位的功能的函数~

要求支持多人~

很容易就想到用计时器呢~这次我们可以试着将数据与计时器绑定起来,从而实现支持多人的说......

很简单的一个小函数呢~很新的新手也完全可以自己试着写写看哦~

利用上面谈到的GetHandleId的特性~

jass
globals
    constant hashtable ht=InitHashtable()
endglobals

function TimerKillUnitCallBack takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local integer id=GetHandleId(t)//这里并不会产生冲突~
    //虽然有多个计时器到期触发该函数~
    //但是它们的【ID都一一不同】~
    //而对应的单位是按照各自ID作为路径存储的~
    //所以每次获取的都是各自的单位,互不冲突的说~
    local unit u=LoadUnitHandle(ht,id,0)
    if (u!=null) then
        call KillUnit(u)
    endif
    call DestroyTimer(t)
    call FlushChildHashtable(ht,id)//清除哈希表中的数据,也是排泄的一部分,初学者容易遗漏~
    set t=null
    set u=null
endfunction

function TimerKillUnit takes unit u,real time returns nothing
    local timer t=CreateTimer()
    local integer id=GetHandleId(t)//计时器的HandleId~
    call SaveUnitHandle(ht,id,0,u) //将计时器的HandleId作为路径,存储单位~
    call TimerStart(t,time,false,function TimerKillUnitCallBack)
    set t=null
endfunction
怎么样?是不是很简单~hashtableGetHandleId配合使用,可以十分轻松地使技能能够支持多人无冲突~

这也素jass技能的魅力之一~

回复 支持 反对

使用道具 举报

管理员

 楼主| 发表于 2018-7-18 15:05:36 | 显示全部楼层
★技能实例~一个简单击退~( 支持多人 )
E.gif
于是来个简单的喵~

所以素被人做烂了的击退呢的说~不过用来上手hashtable应该还素不错的呢~

思路很简单的说~ 单位被攻击->创建计时器->不断朝一个方向移动单位~

所以直接看代码吧~
只素击退而已的说_.w3x (17.54 KB, 下载次数: 1)

jass
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//           【请从最底下开始阅读的说~】
//
//
globals
    constant hashtable ht=InitHashtable()
endglobals

function funcB takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local integer id=GetHandleId(t)
    local integer cnt=LoadInteger(ht,id,0)
    //获取计时器、ID、执行次数~
    local unit u
    local real x
    local real y
    set cnt=cnt+1
    call SaveInteger(ht,id,0,cnt)
    //执行次数增加一次~
    set u=LoadUnitHandle(ht,id,1)
    set x=GetUnitX(u)+LoadReal(ht,id,2)
    set y=GetUnitY(u)+LoadReal(ht,id,3)
    call SetUnitX(u,x)
    call SetUnitY(u,y)
    //移动单位~
    if (cnt-cnt/5*5==0) then
    //这行即cnt mod 5=0时~也就是cnt除以5余数为0~
        call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl",x,y))
    endif
    if (cnt>=30) then
    //到达执行次数上限后销毁计时器,清除哈希表中数据的说~
        call DestroyTimer(t)
        call FlushChildHashtable(ht,id)
    endif
    set u=null
    set t=null
endfunction

function funcA takes nothing returns nothing
    local unit attacker
    local unit target
    local timer t
    local integer id
    local real ang
    set attacker=GetAttacker()
    set target=GetTriggerUnit()
    //获取攻击者和被攻击单位~
    set t=CreateTimer()
    set id=GetHandleId(t)
    //计时器及其句柄ID~
    set ang=Atan2(GetUnitY(target)-GetUnitY(attacker),GetUnitX(target)-GetUnitX(attacker))
    //获取攻击者到被攻击单位的方向~
    call SaveInteger(ht,id,0,0)
    //用于记录计时器执行函数的次数~
    call SaveUnitHandle(ht,id,1,target)
    call SaveReal(ht,id,2,15.0*Cos(ang))
    call SaveReal(ht,id,3,15.0*Sin(ang))
    //单位XY轴方向上的移动速率~
    call TimerStart(t,.02,true,function funcB)
    set attacker=null
    set target=null
    set t=null
    //局部变量排泄~
endfunction

function InitTrig_KnockBack takes nothing returns nothing
    local trigger t=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddAction(t,function funcA)
    set t=null
    //触发器的初始化函数~第一篇教程里面貌似介绍过了的说~
endfunction


★技能实例~幻符「杀人木偶」(进阶)
唔......可怜的门番美玲的说~
话说这技能果断大家都说太难了呐...
没什么算法,但是比较考jass底力,供进阶者参考的说~
A.gif
B.gif
C.gif
D.gif
思路喵~

于是这个技能主要是用一些相同运动模式的小刀组合而成的说~

绕自身旋转着发射小刀~每把小刀先是向外运动一段距离~

然后对随机敌人发射的说~没有敌人则随机散射~
(稍微改了下原作的设定,原作的判定更复杂些呢,还有旋转~
                                                 或者......其实星只素在偷懒的说?)
幻符「杀人木偶」 by wow8 夜の星.w3x (356.25 KB, 下载次数: 4)

唔.......代码也贴出来好了~
jass
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//
//               【请从最底下往上阅读的说~】
//
//
    globals
        constant hashtable ht=InitHashtable()
    endglobals
    //全局的哈希表喵~不解释了哦~
   
    function funcD takes nothing returns nothing
    //计时器周期性执行的函数,控制小刀运动轨迹的说~
        local timer t=GetExpiredTimer()
        local integer id=GetHandleId(t)
        local unit u=LoadUnitHandle(ht,id,1)
        local real x
        local real y
        local integer cnt=LoadInteger(ht,id,0)
        local boolean end
        local group g
        local unit target
        local unit selected
        local integer n
        local player p
        local real a
        set cnt=cnt+1
        call SaveInteger(ht,id,0,cnt)
        //首先读取各类数据,声明变量等等的说~
        set end=(cnt>=100)
        //end变量用于标识小刀是否该结束运动~
        //因为有多个结束运动的条件~所以用一个变量处理较为方便的说~
        if (cnt<=50) then
        //cnt∈[1,50],运动的第一阶段,小刀按扇形轨迹向外扩散的说~
            set x=GetUnitX(u)+LoadReal(ht,id,2)*(75.0-cnt)/75.0
            set y=GetUnitY(u)+LoadReal(ht,id,3)*(75.0-cnt)/75.0
            call SetUnitX(u,x)
            call SetUnitY(u,y)
            //移动单位的说~只素个匀减速运动而已,不懂的童鞋们要补习物理了哦~
            if (cnt==50) then
            //小刀发射前最后一瞬间喵~要锁定一个敌人然后飞过去的说~
                set n=0                      //符合条件的单位计数~后面要用的说~
                set selected=null            //用于存储单位组中随机被选中单位~
                set p=GetOwningPlayer(u)
                set g=CreateGroup()
                call GroupEnumUnitsInRange(g,x,y,1500.0,null)
                //单位组选取的说~不懂的童鞋请复习下上篇教程的说~
                loop
                    //循环遍历单位组中所有单位~同样上篇介绍过了的说~
                    set target=FirstOfGroup(g)
                    exitwhen (target==null)
                    if (IsUnitEnemy(target,p) and  not IsUnitType(target,UNIT_TYPE_DEAD) and  not IsUnitType(target,UNIT_TYPE_FLYING)) then
                        set n=n+1
                        if (GetRandomInt(1,n)==1) then
                            set selected=target
                        endif
                        //第一个单位,100%几率替换之前单位~
                        //第二个单位,50%几率替换~
                        //第三个单位,33%几率替换~
                        //    ......
                        //第N个单位,(100/N)%几率替换~
                        //这样的话,每一个单位最后被选中的概率都素均等的说,数学证明略~
                    endif
                    call GroupRemoveUnit(g,target)
                endloop
                call DestroyGroup(g)
            
                if (selected!=null) then
                //如果周围有符合条件的单位,则角度面向该单位~
                    set a=Atan2(GetUnitY(selected)-y,GetUnitX(selected)-x)
                else
                //如果没有的话,就随便乱飞好了>.<
                    set a=GetRandomReal(0.0,6.283185)
                endif
                call RemoveUnit(u)
                call SaveUnitHandle(ht,id,1,CreateUnit(p,'h000',x,y,a*bj_RADTODEG))
                //重新创建一个小刀,以实现瞬间转向~
                call SaveReal(ht,id,2,50.0*Cos(a))
                call SaveReal(ht,id,3,50.0*Sin(a))
                //重新设定下移动速率的说~
            endif
        else
        //这里就是发射后小刀的运动了喵~
            set p=GetOwningPlayer(u)
            set x=GetUnitX(u)+LoadReal(ht,id,2)
            set y=GetUnitY(u)+LoadReal(ht,id,3)
            call SetUnitX(u,x)
            call SetUnitY(u,y)
            set g=CreateGroup()
            //选取敌人造成伤害~
            call GroupEnumUnitsInRange(g,x,y,75.0,null)
            loop
                set target=FirstOfGroup(g)
                exitwhen (target==null)
                if (IsUnitEnemy(target,p) and  not IsUnitType(target,UNIT_TYPE_DEAD) and  not IsUnitType(target,UNIT_TYPE_FLYING)) then
                    set end=true//打到人了也停止运动的说~
                    call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\BallistaMissile\\BallistaImpact.mdl",x,y))
                    call UnitDamageTarget(u,target,15.0,false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE,WEAPON_TYPE_WHOKNOWS)
                    exitwhen true
                endif
                call GroupRemoveUnit(g,target)
            endloop
            call DestroyGroup(g)
        endif
        if (end) then
        //于是结束了的话,要删掉小刀,销毁计时器并且清除哈希表中数据的说~
            call PauseTimer(t)
            call DestroyTimer(t)
            call FlushChildHashtable(ht,id)
            call KillUnit(u)
        endif
        set t=null
        set u=null
        set g=null
        set target=null
        set p=null
        set selected=null
    endfunction
   
    function funcC takes player p,real x,real y,real a returns nothing
    //喵~于是这里不解释了哦,下面已经说过了呢~
        local timer t=CreateTimer()
        local integer id=GetHandleId(t)
        local unit u
        //这里的计时器用以控制一把小刀的说~
        call SaveInteger(ht,id,0,0)
        set u=CreateUnit(p,'h000',x,y,a*bj_RADTODEG)
        call SaveUnitHandle(ht,id,1,u)
        call SaveReal(ht,id,2,10.0*Cos(a))
        call SaveReal(ht,id,3,10.0*Sin(a))
        //小刀因为是直线运动,所以可以先行算好X轴,Y轴的速率然后分别存储的说~
        call TimerStart(t,0.02,true,function funcD)
        set t=null
        set u=null
    endfunction
   
    function funcB takes nothing returns nothing
    //这个函数就是用于创建环形小刀的~
    //由计时器每隔一段时间到期后调用~
        local timer t=GetExpiredTimer()//到期的计时器~
        local integer id=GetHandleId(t)//获取计时器句柄号~
        local integer cnt=LoadInteger(ht,id,0)
        //我们一开始保存的执行次数,用于累加~
        local unit u
        local real a
        local integer i
        local player p
        local real x
        local real y
        set cnt=cnt+1
        call SaveInteger(ht,id,0,cnt)
        //每次执行次数+1并且保存的说~
        set u=LoadUnitHandle(ht,id,1)
        set a=LoadReal(ht,id,2)+cnt*0.045
        //从哈希表中继续读入数据~
        
        set p=GetOwningPlayer(u)
        set x=GetUnitX(u)
        set y=GetUnitY(u)
        set i=0
        loop
            call funcC(p,x,y,a+3.14159*i)
            //funcC函数是有参数的呢...依次是玩家,X坐标,y坐标以及方向~
            //方向为弧度制~( π 相当于 180°)
            //这里循环两次,角度累加180,相当于是创建两个反向飞行的小刀~
            set i=i+1
            exitwhen (i>1)
        endloop
        
        if (cnt>=40) then
            call PauseTimer(t)
            call DestroyTimer(t)
            call FlushChildHashtable(ht,id)
        endif
        //执行次数达到上限后,销毁计时器~
        //别忘了清空哈希表中数据哦~
        set t=null
        set u=null
        set p=null
    endfunction
   
    function funcA takes nothing returns nothing
        local timer t
        local integer id
        local unit u
        //局部变量声明~
        //必须函数开头,以后就不再讲了的说~
        if (GetSpellAbilityId()!='A000') then
            return        
        endif
        //这次的触发器星没有写条件函数~
        //反正放在动作里面判断一样的说~
        //如果不是A000,则return,退出该函数~
        //没有返回值的函数, return什么都不加即可退出的说~
        set t=CreateTimer()
        set id=GetHandleId(t)
        //创建计时器,获取句柄号~
        //这个计时器用于创建环形的小刀~
        set u=GetTriggerUnit()
        call SaveInteger(ht,id,0,0)
        call SaveUnitHandle(ht,id,1,u)
        call SaveReal(ht,id,2,(GetUnitFacing(u)+90.0)*bj_DEGTORAD)
        //这里就是将执行次数,触发单位(施法者),以及角度存入哈希表~
        //下一个函数中将会用到的说~
        //bj_DEGTORAD:其值等于π(圆周率)/180.0
        //用以将角度制转换为弧度制~
        call TimerStart(t,0.04,true,function funcB)
        //TimerStart应该不用讲了喵~
        //不懂的童鞋请翻阅上篇教程的说~
        set t=null
        set u=null
        //handle型局部变量必须set null排泄~
    endfunction
   
    function InitTrig_TAT takes nothing returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        //为触发器注册任意单位事件~
        //EVENT_PLAYER_UNIT_SPELL_EFFECT 即玩家单位发动技能效果~
        //任意单位事件其实是若干个玩家单位事件组合实现的~
        //嘛,如果不理解也没关系,知道它的功能就行了的说~
        call TriggerAddAction(t,function funcA)
        //为触发器注册动作~
        set t=null
    endfunction


*  技能实例~Lightning Ufo~(喂~没搞错吧?)
ufo.gif
>.<确实是老物了喵~

自己学jass后没多久写的失败作呢的说~(不过作为教学资料还有点利用价值的说~笑~)

复杂度倒是有点呢~不过星觉得,放在这个教程里面还素挺合适的说~(才没想偷懒呢的说!)

嘛,纯粹是过分的jass基本功+熟练度考察,能看懂或者会写这个基本上就已经是相对熟练的状态了~

其实jass技能没什么难的,这样的东西,其实跟着教程学过来的话,素可以看明白甚至自己写的哦~

有能力的童鞋们可以试试看去理解下的说


LightningUFO.w3x (32.96 KB, 下载次数: 2)

于是本篇米有了哦~
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|WOW8论坛  

GMT+8, 2018-8-18 10:59 , Processed in 0.106690 second(s), 6 queries , File On.

WOW8 © 2018

Powered by Discuz! X3.3

快速回复 返回顶部 返回列表