天工维度魔兽争霸开发者社区-全国最大的TJ集中营-原提百万联盟

标题: 计时器模拟 [打印本页]

作者: _何度    时间: 2020-11-19 13:12
标题: 计时器模拟
本帖最后由 _何度 于 2020-11-19 13:30 编辑

lua实现的
计时器系统,就是通常意义的中心计时器,通过对一个 jass的Timer计时器的管理 来虚拟出任意数量的计时器。
基于以下理由,我模拟了这个模块
1.魔兽没有开源,yd源码中也没有 jass计时器的实现,这是一个黑箱。
2.jass计时器 用起来并不顺手,Timer对象占用的资源不理解为什么那么大。
3.jass计时器是多线程实现的,在我的项目中引发了异步问题。

调用接口保留了jass计时器的写法。
用法简介:
1.创建计时器
local New_Timer=CreateTimer()
2.运行计时器(可选择指定计时器 或用一个匿名计时器)
Timer(timeout 到期时间, periodic 是否循环, whichTimer 指定的计时器(可不选) )
(
     --执行函数
     function()

     end,
     --结束条件
     function()
        return 条件表达式
    end
)
用例:
Timer(0.5,true,self.LastTimer)
(
    function()
        total_past=total_past+0.5
        --单位添加引导特效
        if self.buff_factory then
            if self.auto_color then
                self.Lk_color=RandomPick(Ability_link.Colors,true)
            end
            for _,hero in ipairs(self.attach_hero) do
                local target=hero
                local last=0.6
                local compose_type='cover_time'
                local model=self.auto_color and table.concat{'abilityEffect\\LXTX\\',self.Lk_color,'.mdx'} or ''
                local buff=self.buff_factory(target,last,compose_type,model)
                Buff_add(buff)
            end
        end
        if total_past>=self.last then
            self:End_Define()
        end
    end,
    function()
        return total_past>=self.last
    end
)

实现:
--====================require==========================================
local OldCreateTimer=CJ.CreateTimer
local OldTimerStart=CJ.TimerStart
--=====================================================================

local AtomTimer={}
local mt={}
AtomTimer.__index=mt

mt.timeout=-1 --计时器周期

mt.trigleft=-1  --触发剩余时间

mt.periodic=false  --是否循环

mt.condition=nil  --循环的停止条件

mt.id=nil       --计时器标识id

mt.pause=false  --是否暂停

mt.func=nil     --执行函数

mt.removed=false  --是被移除

local TimerEventList={}         --中心计时器事件列表

local ExpiredTimer=nil          --到期的计时器【AtomTimer 类型】

local GameFrames=0.03               --游戏帧数

local GameTimePast=0            --游戏逝去时间

CenterTimer={}                      --中心计时器对象

CenterTimer.handle=OldCreateTimer() --中心计时器jass对象

CenterTimer.Frames=GameFrames       --中心计时器帧数

CenterTimer.ETimerNum=0         --当前有效计时器个数

CenterTimer.runing=false            --是否正在运行

CenterTimer.AtomId=0                --分发的AtomTimerId

CenterTimer.AllTimerList={}         --所有分发的AtomTimer记录

CenterTimer.Start=function()        --运行中心计时器
    OldTimerStart(CenterTimer.handle,CenterTimer.Frames,true,function()
        GameTimePast=GameTimePast+GameFrames
        if #TimerEventList <=0 then
           return
        else
            --print('事件列表长度',#TimerEventList,'运行计时器数目',CenterTimer.ETimerNum)
            for index=1,#TimerEventList do
                --print(index,TimerEventList[index])
                if TimerEventList[index] and not TimerEventList[index].pause then
                    TimerEventList[index].trigleft=TimerEventList[index].trigleft-GameFrames
                    if TimerEventList[index].removed then error('计时器移除异常') end
                    if TimerEventList[index].trigleft<=0 then
                        ExpiredTimer=TimerEventList[index]
                        xpcall(ExpiredTimer.func, function(e) print(debug.traceback()) print('中心计时器-执行函数异常') return e end)
                        if not ExpiredTimer.periodic then
                            ExpiredTimer.removed=true
                            CenterTimer.ETimerNum=CenterTimer.ETimerNum-1
                        else
                            ExpiredTimer.trigleft=ExpiredTimer.timeout
                            if ExpiredTimer.condition and ExpiredTimer.condition() then
                                ExpiredTimer.removed=true
                                CenterTimer.ETimerNum=CenterTimer.ETimerNum-1
                            end
                        end
                    end
                end
            end
            for index=#TimerEventList,1,-1 do
                if TimerEventList[index].removed then
                    table.remove(TimerEventList,index)
                end
            end
        end
    end)
end

function os.clock()             --获取当前游戏时间
    return GameTimePast
end
local CTlock=false          --创建计时器进程锁
function CreateTimer(provideId)        --分配一个计时器对象
    if not CTlock then CTlock=true
    else
        for i=1,8 do
            for j=1,6 do
                CJ.DisplayTimedTextToPlayer(CJ.Player(i-1),0,0,120,'|cFFF00000[错误]:创建计时器进程冲突!!')
            end
        end
        return error('创建计时器进程冲突!!')
    end
    if not provideId then
        CenterTimer.AtomId=CenterTimer.AtomId+1
        provideId=CenterTimer.AtomId
    end
    local atomtimer={id=provideId}
    setmetatable(atomtimer,AtomTimer)
    CenterTimer.ETimerNum=CenterTimer.ETimerNum+1
    CTlock=false
    return atomtimer
end
--运行计时器
---@param timeout integer  周期
---@param periodic boolean 是否循环
---@param whichtimer table 自定义计时器 AtomTimer 对象
---@return table
function Timer(timeout,periodic,whichtimer)
    return function(callback,condition)
        local timer=whichtimer or CreateTimer()
        timer.timeout=timeout
        timer.trigleft=timeout
        timer.periodic=periodic
        timer.func=callback
        timer.condition=condition
        timer.pause=false
        timer.removed=false
        for index,atomtimer in ipairs(TimerEventList) do
            if atomtimer.id==timer.id then
                TimerEventList[index]=timer
                return timer
            end
        end
        table.insert(TimerEventList,timer)
        return timer
    end
end

function DestroyTimer(timer)                --删除计时器
    if Is_intable(TimerEventList,timer) then
        timer.removed=true
        TableRemoveData(TimerEventList,timer)
        CenterTimer.ETimerNum=CenterTimer.ETimerNum-1
    end
end

function PauseTimer (timer)                 --暂停计时器
    timer.pause=true
end

function ResumeTimer (timer)                --恢复计时器
    timer.pause=false
end

function TimerGetRemaining(timer)           --获取计时器剩余时间
    if not timer.removed then
        return timer.trigleft
    else
        return -1
    end
end

function ReCreateTimer(timer)
    DestroyTimer(timer)
    timer.timeout=-1
    timer.trigleft=-1
    timer.periodic=false
    timer.func=nil
    timer.condition=nil
    timer.pause=false
    timer.removed=false
    return timer
end

function GetExpiredTimer()      --获取当前到期的计时器
    return ExpiredTimer
end

function ExtendTime(whichtimer,ExTime)           --延长计时器到期时间
    if not whichtimer.removed then
        whichtimer.trigleft=whichtimer.trigleft+ExTime
        return true
    end
    return false
end

function ReSetTime(whichtimer,time)        --重置计时器到期时间
    if not whichtimer.removed then
        whichtimer.trigleft=time or whichtimer.timeout
        return true
    end
    return false
end


CenterTimer.Start()


print 'timer.lua'



作者: _何度    时间: 2020-11-19 13:27
奈何用不来。
作者: Oo破破oO    时间: 2020-11-19 13:53
用不来你都写出来了- -||
不知道该说你牛还是要说你笨
作者: _何度    时间: 2020-11-19 14:11
Oo破破oO 发表于 2020-11-19 13:53
用不来你都写出来了- -||
不知道该说你牛还是要说你笨

不会用这个网站的代码显示功能
作者: xueyuan1996    时间: 2020-11-19 15:40
有大佬的地方就有我
作者: Mr_小为    时间: 2021-3-10 11:20
Lua版计时器直接用英萌的就行.另外 你Lua版也是用的Jass底层计时器来实现的,无非在写法方面可以扩展一下.

你真要说好处的话,那就是Lua可以随便异步执行闭包

要是有内置的话,Jass都能够实现异步版中心计时器的




欢迎光临 天工维度魔兽争霸开发者社区-全国最大的TJ集中营-原提百万联盟 (http://bbs.mvprpg.com/) Powered by Discuz! X3.4