找回密码
 点一下
查看: 3186|回复: 8

[高级教程]Timer详解(占坑,勿进)

[复制链接]
发表于 2007-12-11 22:32:23 | 显示全部楼层 |阅读模式
提示: 作者被禁止或删除 内容自动屏蔽
发表于 2008-1-7 15:53:33 | 显示全部楼层
大家好,我是everguo,填坑来了~      

以前团团上网不方便,所以我曾叫他把这号密码告诉我,让我帮他发模型和挂在线时间;这次来填坑,由于我不喜欢用马甲,因此借团团的号用下。

好吧,这是最后一章教程,预祝大家早日学成JASS;也请斑竹帮忙加个亮,改下标题(去掉“占坑”)。由于我不打算再“借”团团的号用,因此如果教程中有什么错误或瑕疵,请大家帮忙完善,YD男在此谢谢各位了!


=========================================================JASS培训班专用分割线========================================================


                                                                                                          Timer详解

一、什么是Timer
        timer便是计时器了,但它与我们熟悉的T中的计时器有很大区别,稍后会放上对比。
        timer是JASS精华所在,它能体现JASS高效快捷的特点。很多不错的技能创意,我们难以用T实现;即便我们用T做出来了,别人担心会卡机也不敢放到他们图里。
        或许你对GameCache和Return Bug颇有微词,因此用全局变量数组来替代它们;但没人有过要替代timer的想法,它名声很好,是人见人爱的东东~      
        而且,timer也是无可替代的,它是JASS与T真正的分水岭。
   

二、Timer的使用        
         timer的定义为
[codes=jass]native TimerStart  takes timer whichTimer, real timeout, boolean periodic, code handlerFunc returns nothing[/codes]

         调用方式为
call  TimerStart (计时器,时间间隔,是否循环,函数)

        它是开启一个触发器,让它每隔一段时间就执行次函数;如果只执行一次,那么将boolean型参数设置为false,反之设置为true。

        好了,举个简单的例子,比如我们希望屏幕上每秒出现一行字:“Everguo is handsome!”

那么,我们可以这样做

[codes=jass]function lie takes nothing returns nothing
    call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1,"Everguo is handsome!")
endfunction
                  
function text takes nothing returns nothing
    local timer tm=CreateTimer()
    call TimerStart(tm,1,true,function lie)
    set tm=null
endfunction[/codes]

然后call  text (),屏幕上便会出现字幕。

        从上面的例子我们可以看到,Timer的使用比较简单,与trigger有些类似,这里就不多说了,下面着重将下与Timer有关的数据绑定。

        当屏幕上出现一行行“Everguo is handsome!”,或许大家已经操起板砖打算拍我了;慢……慢着,我把上面函数改下,你们可以把自己名字写进去。

[codes=jass]function H2I takes handle h returns integer
    return h
    return 0
endfunction

function lie takes nothing returns nothing
    local timer tm=GetExpiredTimer()
    local string name=GetStoredString(udg_GC, I2S(H2I(tm)), "Name")
    call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1,name+"is handsome!")
    set tm=null
endfunction
                  
function text takes string name returns nothing
    local timer tm=CreateTimer()
    call StoreString(udg_GC,I2S(H2I(tm)), "Name", name)
    call TimerStart(tm,1,true,function lie)
    set tm=null
endfunction[/codes]

        上面代码是个简单的数据绑定,把string参数绑定给了tm,然后在函数lie中使用GetExpiredTimer() 来获得tm,再从tm上读出数据。
        现在你只需call text("your name"),就会看到有你名字的字幕出现在屏幕上。

       不过你也别高兴得太早,或许细心的朋友已经发现了,那个函数的名字叫“lie”,也就是说一切都是假的^-^
       “谎言重复一千次,就成了真理。” 也就是说,只要执行这段“lie”函数一千次,你就成了帅哥,因此没必要让这函数一直执行下去。
        那么,如何控制函数执行次数呢?
[codes=jass]function H2I takes handle h returns integer
    return h
    return 0
endfunction

function lie takes nothing returns nothing
    local timer tm=GetExpiredTimer()
    local string name=GetStoredString(udg_GC, I2S(H2I(tm)), "Name")
    local integer N=GetStoredInteger(udg_GC, I2S(H2I(tm)), "Number")      
    if N>0 then
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1,name+" is handsome!")
        set N=N-1
        call StoreInteger(udg_GC,I2S(H2I(tm)), "Number",N)
      else
        call FlushStoredMission(udg_GC,I2S(H2I(tm)))
        call DestroyTimer(tm)   
    endif      
    set tm=null
endfunction
                  
function text takes string name,integer N returns nothing
    local timer tm=CreateTimer()
    call StoreString(udg_GC,I2S(H2I(tm)), "Name", name)
    call StoreInteger(udg_GC,I2S(H2I(tm)), "Number", N)
    call TimerStart(tm,1,true,function lie)
    set tm=null
endfunction[/codes]
如上,我们给text函数加了个调用参数,传递显示次数N,并把N绑定给计时器Tm;在lie函数里,函数每执行一次,N就减1,并覆盖缓存中原有的数据“Number”;当N减到0时,不再执行函数,清除缓存中数据,销毁计时器。

        此外,如果你觉得每秒显示次字幕有点快,可以把时间间隔也改成传递过来的参数,如
[codes=jass]function text takes string name,integer N,real timeout returns nothing
    local timer tm=CreateTimer()
    call StoreString(udg_GC,I2S(H2I(tm)), "Name", name)
    call StoreInteger(udg_GC,I2S(H2I(tm)), "Number", N)
    call TimerStart(tm,timeout,true,function lie)
    set tm=null
endfunction[/codes]
现在大家对Timer的使用应该了解了吧,有了它,那我们完全可以屏弃使用TriggerRegisterTimerEvent的写法。

三、用TimerStart替代TriggerRegisterTimerEvent
       TriggerRegisterTimerEvent或许你看起来有些眼生,但TriggerRegisterTimerEventPeriodic我们却经常在T里使用
[trigger]T
    事件
        时间 - 每当过去 2.00 秒游戏时间
    环境        
    动作
       单位 - 创造 1 个 步兵 为了 玩家 1  (红色) 在 point 面对 默认的建筑朝向 度[/trigger]
将其转换成JASS以后,我们得到
[codes=jass]function Trig_T_Actions takes nothing returns nothing
    call CreateNUnitsAtLoc( 1, 'hfoo', Player(0), udg_point, bj_UNIT_FACING )
endfunction

function InitTrig_T takes nothing returns nothing
    set gg_trg_T = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_T, 2 )
    call TriggerAddAction( gg_trg_T, function Trig_T_Actions )
endfunction[/codes]
哦,我们看到了TriggerRegisterTimerEventPeriodic,原来它就是“时间 - 每当过去 XX秒游戏时间”对应的函数啊,大家是不是对它有亲切感~

        那么,TriggerRegisterTimerEventPeriodic与TriggerRegisterTimerEvent区别在哪?
我们在JassShop和JassCraft的查询里里输入“TriggerRegisterTimerEventPeriodic”,得到
[codes=jass]function TriggerRegisterTimerEventPeriodic takes trigger trig, real timeout returns event
    return TriggerRegisterTimerEvent(trig, timeout, true)
endfunction[/codes]
        呵呵,它们的关系不用我多说了吧,调用与被调用的关系——但它们的关系跟BJ函数与CJ函数的关系有些不同。

TriggerRegisterTimerEvent的定义
[codes=jass]native TriggerRegisterTimerEvent takes trigger whichTrigger, real timeout, boolean periodic returns event[/codes]
它比TriggerRegisterTimerEventPeriodic多了个参数boolean periodic,跟timer有些类似,可以选择是执行一次触发器,还是重复执行;而TriggerRegisterTimerEventPeriodic只能重复执行触发器。(注:只让触发器执行一次的BJ函数是TriggerRegisterTimerEventSingle。)

        我向来主张初学者可以适当看下blizzard.j里的函数,但在写代码时尽量用用common.j里的函数;现在我们看下这段代码:
[codes=jass]function Trig_J_Actions takes nothing returns nothing
    call CreateUnitAtLoc( Player(0),'hfoo',udg_point, bj_UNIT_FACING )
endfunction

function CustomTrig_J takes nothing returns nothing
    local trigger trg = CreateTrigger()
    call TriggerRegisterTimerEvent(trg,2,true)
    call TriggerAddAction(trg, function Trig_J_Actions )
    set trg=null
endfunction[/codes]
这段代码不过是上面刷兵函数的另一种写法,不过这种写法要地道得多:使用动态注册事件,用TriggerRegisterTimerEvent替代TriggerRegisterTimerEventPeriodic,用CreateUnitAtLoc替代CreateUnitAtLoc。或许你尚未发现这段代码有何不妥,因为它是很地道的JASS写法;但我只能很遗憾地告诉你——这样写跟用T几乎没区别……

        其实我们可以用timer来替代TriggerRegisterTimerEvent,以体现JASS的高效:
[codes=jass]function CreateUnit_FUN takes nothing returns nothing
    call CreateUnitAtLoc( Player(0),'hfoo',udg_point, bj_UNIT_FACING )
endfunction

function CustomFun_J takes nothing returns nothing
    local timer tm = CreateTimer()
    call TimerStart(tm,2,true,function CreateUnit_FUN)
    set tm=null
endfunction[/codes]
如上,我们生成了个timer来替代trigger,就是把触发器动作里的函数,放到TimerStart中执行;希望大家在处理类似周期性执行函数问题时,能学会用这种用timer替代trigger,用TimerStart替代TriggerRegisterTimerEvent的方法。  

        相信大多数人地图里都有“时间 - 每当过去 XX秒游戏时间”这样的触发器吧,而且这样触发器的数量可能还很多;或许你们听说过,大量使用这样的触发器会使地图变卡,尤其当间隔时间比较短,如“时间 - 每当过去 0.01秒游戏时间”。虽然明知使用这样的触发器不好,但大家却不得不用——比如3C里的定时刷兵,又或者像“跳砍”之类不断移动单位的技能;的确,T已经很强大,可以做出很多东西,但T的执行效率实在让人不敢恭维。因此,不少人是为了让自己地图更流畅,才来学JASS的。

        现在,你已经学到了timer这步,可以把那些以“时间 - 每当过去 XX秒游戏时间”为事件的触发器统统换掉了。另外,即便在同一时间运行大量的timer,地图仍比较流畅。

        那么,为何使用TimerStart效率比TriggerRegisterTimerEvent高,这得从触发器运行原理说起——以之前的刷兵演示为例,刷兵函数作为触发器动作,绑定给触发器;而以TriggerRegisterTimerEven为触发器事件,是每隔一段时间执行次触发器动作;由于触发器动作的执行效率很低,因此老狼甚至建议把动作写到条件里。

四、TimerStrat与StartTimerBJ和的区别        
       从字面意思看,二者都有“timer”和“start”,因此这两个函数应该都是开启计时器的。TimerStart大家不陌生吧,人家刚才违心地管你叫过一千声“帅哥”;那么StartTimerBJ又是何方神圣——从它BJ的后缀来看,它是将T转成J后得到的某个函数。
        或许你已经猜到了——StartTimerBJ便对应T中的倒数计时器。  
        由于前面提过,在执行周期性函数时,用timer比用trigger好,因此有人用倒数计时器来替代TriggerRegisterTimerEventPeriodic——“管它是BJ函数还是CJ函数,管它是TimerStart还是StartTimerBJ,timer的高效总不会变吧;既然在CJ函数里,TimerStart执行效率比TriggerRegisterTimerEvent高,那么在BJ函数里,用StartTimerBJ也一定比用TriggerRegisterTimerEventPeriodic好。”
        是么,那么我们不妨来看下用倒数计时器刷兵的演示;首先我们定义个全局计时器变量tm,令点变量point=(区域 (可玩的地图区域) 的中心),然后
[trigger]initialization
    事件
        地图初始化
    环境
    动作
        倒数计时器 - 开启 tm 为 重复 计时器倒数时间为 10.00 秒
timer
    事件
        时间 - tm 期满
    环境
    动作
        单位 - 创造 1 个 步兵 为了 玩家 1  (红色) 在 point 面对 默认的建筑朝向 度[/trigger]

        上面便是倒数计时器应用的实例。

        由于滥用以“时间 - 每当过去 XX秒游戏时间”为事件的触发器会让地图变卡,因此随后出现一些“用倒数计时器刷兵”的演示,那么,StartTimerBJ是不是真的比TriggerRegisterTimerEventPeriodic高效,我们先来看看StartTimerBJ的定义
[codes=jass]function StartTimerBJ takes timer t, boolean periodic, real timeout returns timer
    set bj_lastStartedTimer = t
    call TimerStart(t, timeout, periodic, null)
    return bj_lastStartedTimer
endfunction[/codes]
首先它让全局变量bj_lastStartedTimer等于传递来的参数t,并把bj_lastStartedTimer返回;当然,这不重要,我们关心的是
[codes=jass]call TimerStart(t, timeout, periodic, null)[/codes]
我们看到,在调TimerStart时,在code那项参数中,需要执行的函数为null;那么,需要被执行的,比如上文的刷兵函数,到哪去了呢——很明显,跟使用TriggerRegisterTimerEventPeriodic时一样,它被放到动作函数里
[trigger]
    动作
        单位 - 创造 1 个 步兵 为了 玩家 1  (红色) 在 point 面对 默认的建筑朝向 度[/trigger]

简而言之,StartTimerBJ跟TriggerRegisterTimerEventPeriodic一样是把函数放触发器动作里,通过执行触发器来执行函数,二者的区别仅仅是触发器事件不同罢了,因此使用StartTimerBJ可谓换汤不换药,并不比使用TriggerRegisterTimerEventPeriodic高效。
        以前在跟人介绍StartTimerBJ时,我曾比喻StartTimerBJ是被阉割了的TimerStart;因为TimerStart中最重要的code参数为null,好比作为男人却没有小JJ一样^-^!

        综上所述,timer只有在JASS里才能发挥最大功能,TimerStart才是王道,让TriggerRegisterTimerEvent跟StartTimerBJ都见鬼去吧!
   
        最后顺带提下,很多朋友不清楚数组尺寸是做什么的,好象设置为0后数组也可正常使用;那么,不知大家注意到没有,在定义局部变量数组时,根本没有数组尺寸这东西——只有在WE里定义全局变量数组才有。一般来说,通常变量数组设置为0即可,惟独group(单位组)、force(玩家组)和timer(计时器)这三种类型的变量,作为数组使用时数组尺寸必须设置正确。

比如,我们定义一个名为timer的全局计时器变量数组,数组尺寸设置为5,那么,地图代码里会多出下面的代码
[codes=jass]globals
    // User-defined
    timer array             udg_timer
endglobals

function InitGlobals takes nothing returns nothing
    local integer i = 0
    set i = 0
    loop
        exitwhen (i > 5)
        set udg_timer = CreateTimer()
        set i = i + 1
    endloop   
endfunction[/codes]

我们看到,"exitwhen (i > 5)"和"set udg_timer = CreateTimer()",也既是说,我们把计时器变量timer的数组尺寸设置为5,那么会生成5个计时器,并且timer[0]、timer[1]…timer[4]均为有效变量,timer[5]就没意义了。

       group和force也有类似性质,大家以后在设置这三种类型变量数组时小心些,数组尺寸一定要设置正确。
回复

使用道具 举报

发表于 2008-1-7 15:54:42 | 显示全部楼层
五、坐标函数        
        现在有了我们timer,再做以前那些卡机技能,比如“跳砍”,每0.01秒移动次单位,系统运行效率可以提高不少呢!那么我再把timer的好朋友——坐标函数介绍给你,它们搭档能进一步提高效率。由于坐标方面的内容比较少,因此我直接放到timer这章一并讲解。
        假如,我们要将一个单位移动到(100,200)这个点,传统做法是
[codes=jass]
local location point = Location(100,200)
call SetUnitPositionLoc( 龙套演员, point )[/codes]

或者,你直接这样写
[codes=jass]call SetUnitPosition(龙套演员,100,200)[/codes]

但上面的写法都不太好,最高效的代码应该这样写
[codes=jass]call SetUnitX(龙套演员,100)
call SetUnitY(龙套演员,200)[/codes]

使用SetUnitPositionLoc非常麻烦,这里就不多说了;现在着重比较下SetUnitX跟SetUnitPositionLoc;老狼做过测试,SetUnitX效率比SetUnitPosition高20倍;按小强的说法,SetUnitPosition要到内存里面搜索实际位置。关于原理,我们没必要去探询;我们只需要知道,使用SetUnitX效率最高,便足够了。

        SetUnitX比起SetUnitPosition除了高效,还有很大的优点——不会打断单位当前order。在使用SetUnitPosition时,我们经常看到单位在抽搐——当山丘哥哥举起“加爵牌”锤子正要敲一个憎恶,突然被SetUnitPosition移动到别的位置,于是举起的手又放了下来;随即它又举起锤子,准备教训下身边的猥琐男,结果又被SetUnitPosition……于是只见山丘不停地把手举起又放下,跟跳健康操似的。而使用SetUnitX,这样说吧,你可以让老虎MM一边围着你旋转一边放流星雨,也可以让巫妖一边凋零别人基地一边后退。
        不过,SetUnitX有个最大的缺陷,那便是,当坐标超出了地图边界,地图会立刻崩溃(试想下,你把单位移动到地图之外,系统能不郁闷到咬舌自尽吗)。因此,使用SetUnitX时必须先判断下坐标是否在超越了地图边界;除此之外,SetUnitX几乎没有其他缺点。

六、实例
        演示永远是最好的教程。
        还记得JASS培训班第一期考试题吗,最后一道,是要求做个冲锋函数。那么,我们一起来做个单位移动函数吧!
        我们知道 路程S=速度V x 时间T,而在这移动函数里,速度V(也就是每秒单位移动的距离)=每次移动位移R x (1/移动时间间隔Timeout);比如,每隔0.02秒移动次单位,每次移动距离为10,那么单位的移动速度V=10 x (1/0.02)=10x50=500,移动10秒,移动距离s=500x10=5000,就这么简单。
        由于那道考试题目中的函数是
[codes=jass]function HeroMoveTimeout takes unit hero,location point,real timeout returns nothing[/codes]
(在确定目的地point后,可以根据单位目前位置,获得距离S;而自定义每次移动位移,根据输入的时间间隔,可以得到速度V;最后我们可根据S=V x T的关系求得时间T,然后用T除以时间间隔timeout获得移动次数。)

因此,为了避免重复(毕竟那是考试题,留给学员做的,所以就不以这个函数为例子),我们换个思路来写移动函数,如
[codes=jass]function UnitMove takes unit orderUnit,real lasttime,real interval,real dis,real angle returns nothing[/codes]
(持续时lasttime便是时间T,angle是移动方向;用移动时间间隔interval和每次移动的距离dis可以求出移动速度V;根据S=V x T求出最终移动距离。)

函数如下
[codes=jass]
function H2I takes handle h returns integer
    return h
    return 0
endfunction

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

function Move_LOOP takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer i = 0
    local unit orderUnit=I2U(GetStoredInteger(udg_GC,I2S(H2I(t)),"orderUnit"))
    local real UnitLocX = GetStoredReal(udg_GC,I2S(H2I(t)),"X")
    local real UnitLocY = GetStoredReal(udg_GC,I2S(H2I(t)),"Y")
    local real tempLocX  
    local real tempLocY  
    local real angle = GetStoredReal(udg_GC,I2S(H2I(t)),"angle")
    local real dis = GetStoredReal(udg_GC,I2S(H2I(t)),"distance")
    local integer steps= GetStoredInteger(udg_GC,I2S(H2I(t)),"steps")
    local integer Max= GetStoredInteger(udg_GC,I2S(H2I(t)),"Max")
    if steps>0  then     
      set steps=steps-1
      call StoreInteger(udg_GC,I2S(H2I(t)),"steps",steps)         
      set tempLocX = UnitLocX + dis*Cos(angle*bj_DEGTORAD)*(Max-steps)
      set tempLocY = UnitLocY + dis*Sin(angle*bj_DEGTORAD)*(Max-steps)   
      if tempLocX > udg_Map_X_Max then
         set tempLocX = udg_Map_X_Max
      endif
      if tempLocX < udg_Map_X_Min then
         set tempLocX = udg_Map_X_Min
      endif
      if tempLocY > udg_Map_Y_Max then
         set tempLocY = udg_Map_Y_Max
      endif
      if tempLocY < udg_Map_Y_Min then
         set tempLocY = udg_Map_Y_Min
      endif               
      call SetUnitX(orderUnit,tempLocX)
      call SetUnitY(orderUnit,tempLocY)     
    else
        set i=0      
        call FlushStoredMission(udg_GC,I2S(H2I(t)))
        call DestroyTimer(t)        
    endif
    set orderUnit=null
endfunction

function UnitMove takes unit orderUnit,real lasttime,real interval,real dis,real angle returns nothing
    local real UnitLocX = GetUnitX(orderUnit)
    local real UnitLocY = GetUnitY(orderUnit)  
    local timer t=CreateTimer()
    local integer steps=R2I(lasttime/interval)
    call StoreReal(udg_GC,I2S(H2I(t)),"X",UnitLocX)
    call StoreReal(udg_GC,I2S(H2I(t)),"Y",UnitLocY)
    call StoreInteger(udg_GC,I2S(H2I(t)),"steps",steps)
    call StoreInteger(udg_GC,I2S(H2I(t)),"Max",steps)
    call StoreReal(udg_GC,I2S(H2I(t)),"angle",angle)
    call StoreReal(udg_GC,I2S(H2I(t)),"distance",dis)
    call StoreInteger(udg_GC,I2S(H2I(t)),"orderUnit",H2I(orderUnit))
    call TimerStart(t,interval,true,function Move_LOOP)
    set t=null
endfunction[/codes]

       首先,利用持续时间lasttime和移动时间间隔interval求出移动次数steps,比如持续10秒,每0.02秒移动次单位,那么这个单位将移动500次,即移动函数被执行500次。
       其次,把所有参数储存到缓存中,用TimerStart循环执行函数Move_LOOP。
       最后,在Move_LOOP中,从缓存中读出数据;函数每被执行依次,就让steps减1,直到为0;特别一提的是,必须让单位的坐标tempLocX和tempLocY跟地图边界比较,边界值由全局变量Map_X_Min、Map_X_Max、Map_Y_Min和Map_Y_Max保存。

       上面函数看起来代码冗长,其实内容很简单,只不断从缓存中读取和写入数据以致繁琐。

现在我们再看一个旋转函数。其实很简单,把上面的代码稍微改下就是了。
[codes=jass]function H2I takes handle h returns integer
    return h
    return 0
endfunction

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

function Circle_LOOP takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer i = 0
    local unit OrderUnit=I2U(GetStoredInteger(udg_GC,I2S(H2I(t)),"OrderUnit"))
    local unit CircleUnit=I2U(GetStoredInteger(udg_GC,I2S(H2I(t)),"CircleUnit"))
    local real UnitLocX = GetUnitX(OrderUnit)
    local real UnitLocY = GetUnitY(OrderUnit)
    local real tempLocX  
    local real tempLocY  
    local real AngleSpeed = GetStoredReal(udg_GC,I2S(H2I(t)),"AngleSpeed")
    local real radius = GetStoredReal(udg_GC,I2S(H2I(t)),"radius")
    local real AngleSpeed = GetStoredReal(udg_GC,I2S(H2I(t)),"AngleSpeed")   
    local real degrees = GetStoredReal(udg_GC,I2S(H2I(t)),"degrees")         
    local integer steps= GetStoredInteger(udg_GC,I2S(H2I(t)),"steps")
    if steps>0  then     
      set steps=steps-1
      call StoreInteger(udg_GC,I2S(H2I(t)),"steps",steps)
      set degrees=degrees+AngleSpeed
      set tempLocX = UnitLocX + radius*Cos(degrees*3.14159/180.0)      
      set tempLocY = UnitLocY + radius*Sin(degrees*3.14159/180.0)           
      if tempLocX > udg_Map_X_Max then
         set tempLocX = udg_Map_X_Max
      endif
      if tempLocX < udg_Map_X_Min then
         set tempLocX = udg_Map_X_Min
      endif
      if tempLocY > udg_Map_Y_Max then
         set tempLocY = udg_Map_Y_Max
      endif
      if tempLocY < udg_Map_Y_Min then
         set tempLocY = udg_Map_Y_Min
      endif               
      call SetUnitX(CircleUnit,tempLocX)
      call SetUnitY(CircleUnit,tempLocY)     
    else
        set i=0      
        call FlushStoredMission(udg_GC,I2S(H2I(t)))
        call DestroyTimer(t)        
    endif
    set orderUnit=null
    set CircleUnit=null
endfunction

function UnitCircle takes unit OrderUnit,unit CircleUnit,real lasttime,real interval,real radius,real AngleSpeed returns nothing
    local timer t=CreateTimer()
    local integer steps=R2I(lasttime/interval)
    call StoreInteger(udg_GC,I2S(H2I(t)),"steps",steps)
    call StoreReal(udg_GC,I2S(H2I(t)),"radius",radius)
    call StoreReal(udg_GC,I2S(H2I(t)),"AngleSpeed",AngleSpeed)
    call StoreInteger(udg_GC,I2S(H2I(t)),"OrderUnit",H2I(OrderUnit))
    call StoreInteger(udg_GC,I2S(H2I(t)),"CircleUnit",H2I(CircleUnit))
    call TimerStart(t,interval,true,function Circle_LOOP)
    set t=null
endfunction[/codes]

        该函数的作用是让一个单位绕另一个单位旋转,可以设置旋转持续时间lasttime,旋转角速度AngleSpeed等;我们只是修改了前个函数中计算坐标的部分代码,其余部分都大同小异。篇幅所限,我就只介绍这两个函数函数,学员可找更多跟timer有关的演示来学习。

         好了,老规矩,放上演示供大家参考。
   
        最后罗嗦两句,希望这个JASS培训班能越来越火,希望JASS高手能抽时间指点下新人,希望新人能多提问积极地学习。末了,祝大家新年快乐!

JASS培训班——Timer.w3x

24 KB, 下载次数: 27

回复

使用道具 举报

发表于 2008-1-7 15:55:20 | 显示全部楼层
everguo大人终于来填坑了~~感动中………………
回复

使用道具 举报

发表于 2008-1-7 16:28:25 | 显示全部楼层
坑道补完计划。。。
回复

使用道具 举报

发表于 2008-1-7 16:41:36 | 显示全部楼层
也祝您新年快乐!
回复

使用道具 举报

发表于 2008-1-14 22:35:34 | 显示全部楼层
嗯,很好,很强大...偶像.,.
回复

使用道具 举报

发表于 2008-1-15 16:38:20 | 显示全部楼层
膜拜... 膜拜中..
回复

使用道具 举报

发表于 2008-1-15 18:23:25 | 显示全部楼层
同膜拜………………
继续膜拜………………
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-5-16 04:20 , Processed in 0.220109 second(s), 21 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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