找回密码
 点一下
查看: 5076|回复: 21

共享一个【中心计时器】的JASS实现

[复制链接]
发表于 2010-12-7 21:01:50 | 显示全部楼层 |阅读模式
关于中心计时器 -- 个人理解中心计时器就是用一个计时器来完成一些延迟性任务,比如我以前喜欢设置当一个单位死亡后等待5秒删除这个单位。
但是调用PolledWait这个方法会创建Timer然后销毁一个(听说如果反复这样做的话会导致大量系统开销而且不精准),所以就要自己创建一个Timer
然后等待Timer到期后执行这个删除单位的方法,可是这样就很有局限性,而且如果拿他来删除别的比如效果什么的重复代码要写很多的。中心计时器
的概念就诞生了,当然这个不是我的创意,我只是偶尔看到别人提出了这个概念之后自己用自己的方法实现了一个而已,下面来看看代码吧


这个由于不太会T所以就只能用JASS了,如果大家觉得还不错,就请那位大侠把它用T实现一下吧。。。

[jass]
//====================================================================================================
//
//  一些存取运行触发器属性的方法
//
//====================================================================================================
//设置触发器是否周期性执行
function SetTCTriggerIsPeriodic takes trigger trig,boolean b returns nothing
    call SaveBooleanLJ(trig,"TC_TrigPeriodic",b)
endfunction
//设置触发器执行延迟时间
function SetTCTriggerTimeout takes trigger trig,integer b returns nothing
    call SaveIntegerLJ(trig,"TC_TrigTimeout",b)
endfunction
//设置触发器是否启用
function SetTCTriggerEnable takes trigger trig,boolean b returns nothing
    call SaveBooleanLJ(trig,"TC_TrigEnable",b)
endfunction
//设置触发器周期次数
function SetTCTriggerRuncount takes trigger trig,integer b returns nothing
    call SaveIntegerLJ(trig,"TC_TrigRuncount",b)
endfunction
//取得触发器是否周期性执行
function TCTriggerIsPeriodic takes trigger trig returns boolean
    return LoadBooleanLJ(trig,"TC_TrigPeriodic")
endfunction
//取得触发器执行延迟时间
function GetTCTriggerTimeout takes trigger trig returns integer
    return LoadIntegerLJ(trig,"TC_TrigTimeout")
endfunction
//取得触发器是否启用
function TCTriggerIsEnable takes trigger trig returns boolean
    return LoadBooleanLJ(trig,"TC_TrigEnable")
endfunction
//取得触发器周期次数
function GetTCTriggerRuncount takes trigger trig returns integer
    return LoadIntegerLJ(trig,"TC_TrigRuncount")
endfunction
//====================================================================================================
//
//  注册使用中心计时器
//
//====================================================================================================
//对内注册方法
function P_TimerCenterStart takes integer timeout,boolean periodic,integer runcount,trigger trig returns nothing
    local integer i = 1
    local integer runtime
    //设置触发器非关闭状态
    call SetTCTriggerEnable(trig,false)
    //设置触发器是否周期性执行
    call SetTCTriggerIsPeriodic(trig,periodic)
    //设置触发器周期运行间隔
    call SetTCTriggerTimeout(trig,timeout)
    //设置触发器周期次数
    call SetTCTriggerRuncount(trig,runcount)
    //设置下次触发器何时运行
    set runtime = udg_LJ_TimerCenterCount + timeout
    loop
        if not(HaveSavedHandle(udg_LJ_TimerCenterCache,runtime,i)) then
            call SaveTriggerHandle(udg_LJ_TimerCenterCache,runtime,i,trig)
            call SaveInteger(udg_LJ_TimerCenterCache,runtime,0,LoadInteger(udg_LJ_TimerCenterCache,runtime,0)+1)
            exitwhen true
        endif
        set i = i + 1
    endloop
endfunction
//对外注册方法   timeout 周期间隔时间  periodic 是否周期循环  runcount 执行次数如果 periodic为true则忽略次数 trig 执行的触发器
function TimerCenterStart takes real timeout,boolean periodic,integer runcount,trigger trig returns nothing
    call P_TimerCenterStart(R2I(timeout*100),periodic,runcount,trig)
endfunction
//====================================================================================================
//
//  中心计时器动作
//
//====================================================================================================
function ActionTimerCenterLJ takes nothing returns nothing
    local trigger trig             //触发器索引
    local integer i = 1
    local integer trigListSize     //当前时间点上的触发器集合大小
    local integer runcount         //累计运行次数
    //中心计时器计数器
    set udg_LJ_TimerCenterCount = udg_LJ_TimerCenterCount + 1
    //当前时间点上触发器集合大小用0下标来存储,所以触发器是从1开始存储的
    set trigListSize = LoadInteger(udg_LJ_TimerCenterCache,udg_LJ_TimerCenterCount,0)
    //如果当前时间点的触发器集合大小不等于0,则开始处理
    if trigListSize != 0 then
        loop
            //获得当前时间点的第i个触发器
            set trig = LoadTriggerHandle(udg_LJ_TimerCenterCache,udg_LJ_TimerCenterCount,i)
            //判断当前的触发器是否可以运行
            if trig != null then
                //循环运行统计数
                set runcount = GetTCTriggerRuncount(trig)
                if runcount > 0 and not(TCTriggerIsEnable(trig)) then
                    call TriggerExecute(trig)
                    set runcount = runcount - 1
                    if TCTriggerIsPeriodic(trig) or runcount > 0 then
                        call P_TimerCenterStart(GetTCTriggerTimeout(trig),true,runcount,trig)
                    endif
                endif
            endif
        //循环退出条件,所有的触发器都被执行过
        exitwhen trigListSize == i
        set i = i + 1
        endloop
    endif
    //清理当前时间点上所有的触发器
    call FlushChildHashtable(udg_LJ_TimerCenterCache,udg_LJ_TimerCenterCount)
    //Clear
    set trig = null
endfunction
//====================================================================================================
//
//  初始化中心计时器
//
//====================================================================================================
function InitTimerCenterLJ takes nothing returns nothing
    //初始化中心计时器哈希表
    if udg_LJ_TimerCenterCache == null then
        set udg_LJ_TimerCenterCache = InitHashtable()
    endif
    //初始化中心计时器
    if udg_LJ_TimerCenter == null then
        set udg_LJ_TimerCenter = CreateTimer()
    endif
    set udg_LJ_TimerCenterCount = 0 //初始化中心计时器计数器
    call TimerStart(udg_LJ_TimerCenter,.01,true,function ActionTimerCenterLJ)
endfunction


[/jass]



用例代码


[jass]
//执行触发器100次  
local trigger t = CreateTrigger()   
call TriggerAddAction(t,function test1)   
call SavePlayerLJ(t,"Player",p)   
call TimerCenterStart(.01,false,100,t)
[/jass]

评分

参与人数 1威望 +2 收起 理由
疯人¢衰人 + 2 很久没人发系统了

查看全部评分

发表于 2010-12-8 00:19:13 | 显示全部楼层
楼主有心了,Keyword都有设置...

从头到尾看了一遍... 觉得是很不错的东西,不过觉得野生timer也不是很麻烦。
不过记得最小精度不是0.01,这里
call P_TimerCenterStart(R2I(timeout*100),perio...
会导致导致误差么?
SaveXxxLJ?………………应该是仿GC函数吧?

hmmm... 不过按这个思路,自己DIY一个简化版的的确可以砍掉不少行呢...
回复

使用道具 举报

发表于 2010-12-8 00:21:02 | 显示全部楼层
PS...

GA的话,jass可以用[jass]代替[code]的说...
回复

使用道具 举报

发表于 2010-12-8 04:08:38 | 显示全部楼层
中心计时器这个东西,容易找到的来源是ydwe。在我看来中心计时器这种想法很不错,但是实用性不高。用来解析执行对象的代码的消耗早已大于多个timer自身的消耗了。唯一有利的使用情况是多对象倍率周期的情况,例如模拟弹幕。
回复

使用道具 举报

 楼主| 发表于 2010-12-8 08:43:34 | 显示全部楼层

回 1楼(Conflux) 的帖子

小试了一下,暂时还没发现延迟的情况主要是因为hash里面存放的索引必须是int的吗,所以我想就不要转换了索性就用*100来解决这个问题吧。。。如果红眼有什么好想法请告诉我哦,非常关注你的意见。SaveXxxLJ 确实是hashtable版的存取函数
回复

使用道具 举报

 楼主| 发表于 2010-12-8 08:44:30 | 显示全部楼层

回 3楼(疯人¢衰人) 的帖子

多谢疯人的提醒,所以我就是想找到个简单的解析算法能尽量减少解析过程的资源消耗。
回复

使用道具 举报

 楼主| 发表于 2010-12-8 20:03:05 | 显示全部楼层

回 6楼(2593126) 的帖子

是不是循环的速度太快了。。。慢一点的话30个应该可以的。。。而且我觉得用单位环绕的话,确实比较耗费资源因为单位这个东西本来就消耗资源,如果单单能让效果移动就好了。。。。
回复

使用道具 举报

发表于 2010-12-8 21:12:30 | 显示全部楼层
那个是用了gc的缘故吧,找一下弹幕图,那么多都不会卡。
解析方法在于排序。也就是下一次到期的计时器的执行对象。感觉上做一个单向链表就行了,不过j下维护这个表太低效,加之动态添加执行内容只能用trigger,效率更低。
还是想办法排泄好timer好了
回复

使用道具 举报

发表于 2010-12-9 00:23:23 | 显示全部楼层
疯的ID太不美了太不美了...
回复

使用道具 举报

发表于 2010-12-9 07:18:59 | 显示全部楼层
疯子是某位小c……弹幕图没用vj,纯数组,作者不会vj
回复

使用道具 举报

 楼主| 发表于 2010-12-9 08:54:30 | 显示全部楼层
楼上你们说的弹幕到底是什么东西呀?能给个传送门不?
回复

使用道具 举报

发表于 2010-12-9 12:57:06 | 显示全部楼层
他的算法是根据不同单位单独写的,不需要复杂系统
回复

使用道具 举报

 楼主| 发表于 2010-12-9 13:47:16 | 显示全部楼层
对不起呀,不知道是那个弹幕呀?搜索了一下居然有好几个。。。。都不知道是那个呀?
回复

使用道具 举报

发表于 2010-12-9 14:16:19 | 显示全部楼层
弦凝绝……作者的名字
回复

使用道具 举报

 楼主| 发表于 2010-12-9 14:25:05 | 显示全部楼层

回 17楼(疯人¢衰人) 的帖子

有魔兽争霸版的吗?它那个是星际2的吧。。。
回复

使用道具 举报

发表于 2010-12-9 16:20:07 | 显示全部楼层
有……,没发到ga么?
回复

使用道具 举报

发表于 2010-12-9 18:24:04 | 显示全部楼层
何必这么麻烦,楼主举的例子,把要操作的单位记录到一个队列里去,然后用一个timer管理这个队列,不就可以了?
回复

使用道具 举报

 楼主| 发表于 2010-12-10 08:53:09 | 显示全部楼层

回 20楼(actboy168) 的帖子

做这个的目的是为了通用性,这样就可以动态的注册自己需要循环的方法了,比如删除效果,冲锋,单位环绕。。。如果每一个都创建一个timer加一个队列的话,代码会不会很重复呢?
回复

使用道具 举报

发表于 2010-12-10 12:57:10 | 显示全部楼层
通用和效率是一对矛盾的组合

要通用的话,暴雪管理timer大概也是类似的方法,所以自己管理不见得就比交给魔兽管理好。
回复

使用道具 举报

 楼主| 发表于 2010-12-10 21:12:59 | 显示全部楼层

回 22楼(actboy168) 的帖子

说的也是,不过为了编程方便,加上减少对象的重复创建,中心计时器还是有它的价值的吧。。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-2 23:18 , Processed in 0.139748 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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