-- 定时器管理:负责定时器获取、回收、缓存、调度等管理
-- 注意:
-- 1、任何需要定时更新的函数从这里注册,游戏逻辑层最好使用不带"Co"的接口
-- 2、带有"Co"的接口都是用于协程,它的调度会比普通更新后一步---次序依从Unity函数调用次序:https://docs.unity3d.com/Manual/ExecutionOrder.html
-- 3、UI界面倒计时刷新等不需要每帧去更新的逻辑最好用定时器,少用Updatable,定时器能很好避免频繁的无用调用
-- 4、定时器并非精确定时,误差范围和帧率相关
-- 5、循环定时器不会累积误差,这点和Updater的Update函数自己去控制时间刷新是一致的,很好用
-- 6、定时器是weak表,使用临时对象时不会持有引用
-- 7、慎用临时函数、临时闭包,所有临时对象要外部自行维护引用以保障生命周期,否则会被GC掉===>很重要***
-- 8、考虑到定时器可能会被频繁构造、回收,这里已经做了缓存池优化
支付宝捐赠
- TimerManager.lua
--[[
-- 定时器管理:负责定时器获取、回收、缓存、调度等管理
-- 注意:
-- 1、任何需要定时更新的函数从这里注册,游戏逻辑层最好使用不带"Co"的接口
-- 2、带有"Co"的接口都是用于协程,它的调度会比普通更新后一步---次序依从Unity函数调用次序:https://docs.unity3d.com/Manual/ExecutionOrder.html
-- 3、UI界面倒计时刷新等不需要每帧去更新的逻辑最好用定时器,少用Updatable,定时器能很好避免频繁的无用调用
-- 4、定时器并非精确定时,误差范围和帧率相关
-- 5、循环定时器不会累积误差,这点和Updater的Update函数自己去控制时间刷新是一致的,很好用
-- 6、定时器是weak表,使用临时对象时不会持有引用
-- 7、慎用临时函数、临时闭包,所有临时对象要外部自行维护引用以保障生命周期,否则会被GC掉===>很重要***
-- 8、考虑到定时器可能会被频繁构造、回收,这里已经做了缓存池优化
--]]
local Messenger = require "Framework.Common.Messenger"
local TimerManager = BaseClass("TimerManager", Singleton)
local UpdateMsgName = "Update"
-- 构造函数
local function __init(self)
-- 成员变量
-- handle
self.__update_handle = nil
self.__lateupdate_handle = nil
self.__fixedupdate_handle = nil
self.__coupdate_handle = nil
self.__colateupdate_handle = nil
self.__cofixedupdate_handle = nil
-- 定时器列表
self.__update_timer = {}
self.__lateupdate_timer = {}
self.__fixedupdate_timer = {}
self.__coupdate_timer = {}
self.__colateupdate_timer = {}
self.__cofixedupdate_timer = {}
-- 定时器缓存
self.__pool = {}
-- 待添加的定时器列表
self.__update_toadd = {}
self.__lateupdate_toadd = {}
self.__fixedupdate_toadd = {}
self.__coupdate_toadd = {}
self.__colateupdate_toadd = {}
self.__cofixedupdate_toadd = {}
end
-- 延后回收定时器,必须全部更新完毕再回收,否则会有问题
local function DelayRecycle(self, timers)
for timer,_ in pairs(timers) do
if timer:IsOver() then
timer:Stop()
table.insert(self.__pool, timer)
timers[timer] = nil
end
end
end
-- Update回调
local function UpdateHandle(self)
-- 更新定时器
for timer,_ in pairs(self.__update_toadd) do
self.__update_timer[timer] = true
self.__update_toadd[timer] = nil
end
for timer,_ in pairs(self.__update_timer) do
timer:Update(false)
end
DelayRecycle(self, self.__update_timer)
end
-- LateUpdate回调
local function LateUpdateHandle(self)
-- 更新定时器
for timer,_ in pairs(self.__lateupdate_toadd) do
self.__lateupdate_timer[timer] = true
self.__lateupdate_toadd[timer] = nil
end
for timer,_ in pairs(self.__lateupdate_timer) do
timer:Update(false)
end
DelayRecycle(self, self.__lateupdate_timer)
end
-- FixedUpdate回调
local function FixedUpdateHandle(self)
-- 更新定时器
for timer,_ in pairs(self.__fixedupdate_toadd) do
self.__fixedupdate_timer[timer] = true
self.__fixedupdate_toadd[timer] = nil
end
for timer,_ in pairs(self.__fixedupdate_timer) do
timer:Update(true)
end
DelayRecycle(self, self.__fixedupdate_timer)
end
-- CoUpdate回调
local function CoUpdateHandle(self)
-- 更新定时器
for timer,_ in pairs(self.__coupdate_toadd) do
self.__coupdate_timer[timer] = true
self.__coupdate_toadd[timer] = nil
end
for timer,_ in pairs(self.__coupdate_timer) do
timer:Update(false)
end
DelayRecycle(self, self.__coupdate_timer)
end
-- CoLateUpdate回调
local function CoLateUpdateHandle(self)
-- 更新定时器
for timer,_ in pairs(self.__colateupdate_toadd) do
self.__colateupdate_timer[timer] = true
self.__colateupdate_toadd[timer] = nil
end
for timer,_ in pairs(self.__colateupdate_timer) do
timer:Update(false)
end
DelayRecycle(self, self.__colateupdate_timer)
end
-- CoFixedUpdate回调
local function CoFixedUpdateHandle(self)
-- 更新定时器
for timer,_ in pairs(self.__cofixedupdate_toadd) do
self.__cofixedupdate_timer[timer] = true
self.__cofixedupdate_toadd[timer] = nil
end
for timer,_ in pairs(self.__cofixedupdate_timer) do
timer:Update(true)
end
DelayRecycle(self, self.__cofixedupdate_timer)
end
-- 启动
local function Startup(self)
self:Dispose()
self.__update_handle = UpdateBeat:CreateListener(UpdateHandle, TimerManager:GetInstance())
self.__lateupdate_handle = LateUpdateBeat:CreateListener(LateUpdateHandle, TimerManager:GetInstance())
self.__fixedupdate_handle = FixedUpdateBeat:CreateListener(FixedUpdateHandle, TimerManager:GetInstance())
self.__coupdate_handle = CoUpdateBeat:CreateListener(CoUpdateHandle, TimerManager:GetInstance())
self.__colateupdate_handle = CoLateUpdateBeat:CreateListener(CoLateUpdateHandle, TimerManager:GetInstance())
self.__cofixedupdate_handle = CoFixedUpdateBeat:CreateListener(CoFixedUpdateHandle, TimerManager:GetInstance())
UpdateBeat:AddListener(self.__update_handle)
LateUpdateBeat:AddListener(self.__lateupdate_handle)
FixedUpdateBeat:AddListener(self.__fixedupdate_handle)
CoUpdateBeat:AddListener(self.__coupdate_handle)
CoLateUpdateBeat:AddListener(self.__colateupdate_handle)
CoFixedUpdateBeat:AddListener(self.__cofixedupdate_handle)
end
-- 释放
local function Dispose(self)
if self.__update_handle ~= nil then
UpdateBeat:RemoveListener(self.__update_handle)
self.__update_handle = nil
end
if self.__lateupdate_handle ~= nil then
LateUpdateBeat:RemoveListener(self.__lateupdate_handle)
self.__lateupdate_handle = nil
end
if self.__fixedupdate_handle ~= nil then
FixedUpdateBeat:RemoveListener(self.__fixedupdate_handle)
self.__fixedupdate_handle = nil
end
if self.__coupdate_handle ~= nil then
CoUpdateBeat:RemoveListener(self.__coupdate_handle)
self.__coupdate_handle = nil
end
if self.__colateupdate_handle ~= nil then
CoLateUpdateBeat:RemoveListener(self.__colateupdate_handle)
self.__colateupdate_handle = nil
end
if self.__cofixedupdate_handle ~= nil then
CoFixedUpdateBeat:RemoveListener(self.__cofixedupdate_handle)
self.__cofixedupdate_handle = nil
end
end
-- 清理:可用在场景切换前,不清理关系也不大,只是缓存池不会下降
local function Cleanup(self)
self.__update_timer = {}
self.__lateupdate_timer = {}
self.__fixedupdate_timer = {}
self.__coupdate_timer = {}
self.__colateupdate_timer = {}
self.__cofixedupdate_timer = {}
self.__pool = {}
self.__update_toadd = {}
self.__lateupdate_toadd = {}
self.__fixedupdate_toadd = {}
self.__coupdate_toadd = {}
self.__colateupdate_toadd = {}
self.__cofixedupdate_toadd = {}
end
-- 获取定时器
local function InnerGetTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
local timer = nil
if table.length(self.__pool) > 0 then
timer = table.remove(self.__pool)
if delay and func then
timer:Init(delay, func, obj, one_shot, use_frame, unscaled)
end
else
timer = Timer.New(delay, func, obj, one_shot, use_frame, unscaled)
end
return timer
end
-- 获取Update定时器
local function GetTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
assert(not self.__update_timer[timer] and not self.__update_toadd[timer])
local timer = InnerGetTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
self.__update_toadd[timer] = true
return timer
end
-- 获取LateUpdate定时器
local function GetLateTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
assert(not self.__lateupdate_timer[timer] and not self.__lateupdate_toadd[timer])
local timer = InnerGetTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
self.__lateupdate_toadd[timer] = true
return timer
end
-- 获取FixedUpdate定时器
local function GetFixedTimer(self, delay, func, obj, one_shot, use_frame)
assert(not self.__fixedupdate_timer[timer] and not self.__fixedupdate_toadd[timer])
local timer = InnerGetTimer(self, delay, func, obj, one_shot, use_frame, false)
self.__fixedupdate_toadd[timer] = true
return timer
end
-- 获取CoUpdate定时器
local function GetCoTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
assert(not self.__coupdate_timer[timer] and not self.__coupdate_toadd[timer])
local timer = InnerGetTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
self.__coupdate_toadd[timer] = true
return timer
end
-- 获取CoLateUpdate定时器
local function GetCoLateTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
assert(not self.__colateupdate_timer[timer] and not self.__colateupdate_toadd[timer])
local timer = InnerGetTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
self.__colateupdate_toadd[timer] = true
return timer
end
-- 获取CoFixedUpdate定时器
local function GetCoFixedTimer(self, delay, func, obj, one_shot, use_frame)
assert(not self.__cofixedupdate_timer[timer] and not self.__cofixedupdate_toadd[timer])
local timer = InnerGetTimer(self, delay, func, obj, one_shot, use_frame, unscaled)
self.__cofixedupdate_toadd[timer] = true
return timer
end
-- 析构函数
local function __delete(self)
self:Cleanup()
self.__update_handle = nil
self.__lateupdate_handle = nil
self.__fixedupdate_handle = nil
self.__coupdate_handle = nil
self.__colateupdate_handle = nil
self.__cofixedupdate_handle = nil
self.__update_timer = nil
self.__lateupdate_timer = nil
self.__fixedupdate_timer = nil
self.__coupdate_timer = nil
self.__colateupdate_timer = nil
self.__cofixedupdate_timer = nil
self.__pool = nil
self.__update_toadd = nil
self.__lateupdate_toadd = nil
self.__fixedupdate_toadd = nil
self.__coupdate_toadd = nil
self.__colateupdate_toadd = nil
self.__cofixedupdate_toadd = nil
end
TimerManager.__init = __init
TimerManager.Startup = Startup
TimerManager.Cleanup = Cleanup
TimerManager.Dispose = Dispose
TimerManager.GetTimer = GetTimer
TimerManager.GetLateTimer = GetLateTimer
TimerManager.GetFixedTimer = GetFixedTimer
TimerManager.GetCoTimer = GetCoTimer
TimerManager.GetCoLateTimer = GetCoLateTimer
TimerManager.GetCoFixedTimer = GetCoFixedTimer
TimerManager.__delete = __delete
return TimerManager;
- Timer.lua
--[[
-- 定时器
-- 注意:
-- 1、定时器需要暂停使用pause、恢复使用resume
-- 2、定时器使用stop停止,一旦停止逻辑层脚本就应该将引用置空,因为它随后会被管理类回收,引用已经不再正确
--]]
local Timer = BaseClass("Timer")
-- 构造函数
local function __init(self, delay, func, obj, one_shot, use_frame, unscaled)
-- 成员变量
-- weak表,保证定时器不影响目标对象的回收
self.target = setmetatable({}, {__mode = "v"})
if delay and func then
self:Init(delay, func, obj, one_shot, use_frame, unscaled)
end
end
-- Init
local function Init(self, delay, func, obj, one_shot, use_frame, unscaled)
assert(type(delay) == "number" and delay >= 0)
assert(func ~= nil)
-- 时长,秒或者帧
self.delay = delay
-- 回调函数
self.target.func = func
-- 回传对象,一般作为回调函数第一个self参数
self.target.obj = obj
-- 是否是一次性计时
self.one_shot = one_shot
-- 是否是帧定时器,否则为秒定时器
self.use_frame = use_frame
-- 使用deltaTime计时,还是采用unscaledDeltaTime计时
self.unscaled = unscaled
-- 是否已经启用
self.started = false
-- 倒计时
self.left = delay
-- 是否已经结束
self.over = false
-- 传入对象是否为空
self.obj_not_nil = obj and true or false
-- 启动定时器时的帧数
self.start_frame_count = Time.frameCount
end
-- Update
local function Update(self, is_fixed)
if not self.started or self.over then
return
end
local timeup = false
if self.use_frame then
-- TODO:这里有个经常会落后一帧的问题,一般出现在协程当中--当协程启用另外的协程时
-- 协程不做精确定时,一般用于异步等待或者分帧操作,所以这里暂时没有什么影响,后面看是否需要修改
timeup = (Time.frameCount >= self.start_frame_count + self.delay)
else
local delta = nil
if is_fixed then
delta = Time.fixedDeltaTime
else
delta = not self.unscaled and Time.deltaTime or Time.unscaledDeltaTime
end
self.left = self.left - delta
timeup = (self.left <= 0)
end
if timeup then
if self.target.func ~= nil then
-- 说明:这里一定要先改状态,后回调
-- 如果回调手动删除定时器又马上再次获取,则可能得到的是同一个定时器,再修改状态就不对了
-- added by Circle @ 2018-01-09:TimerManager已经被重构,不存在以上问题,但是这里的代码不再做调整
if not self.one_shot then
if not self.use_frame then
-- 说明:必须把上次计时“欠下”的时间考虑进来,否则会有误差
self.left = self.delay + self.left
end
self.start_frame_count = Time.frameCount
else
self.over = true
end
-- 说明:运行在保护模式,有错误也只是停掉定时器,不要让客户端挂掉
local status, err
if self.obj_not_nil then
status, err = pcall(self.target.func, self.target.obj)
else
status, err = pcall(self.target.func)
end
if not status then
self.over = true
Logger.LogError(err)
end
else
self.over = true
end
end
end
-- 启动计时
local function Start(self)
if self.over then
Logger.LogError("You can't start a overed timer, try add a new one!")
end
if not self.started then
self.left = self.delay
self.started = true
self.start_frame_count = Time.frameCount
end
end
-- 暂停计时
local function Pause(self)
self.started = false
end
-- 恢复计时
local function Resume(self)
self.started = true
end
-- 停止计时
local function Stop(self)
self.left = 0
self.one_shot = false
self.target.func = nil
self.target.obj = nil
self.use_frame = false
self.unscaled = false
self.started = false
self.over = true
end
-- 复位:如果计时器是启动的,并不会停止,只是刷新倒计时
local function Reset(self)
self.left = self.delay
self.start_frame_count = Time.frameCount
end
-- 是否已经完成计时
local function IsOver(self)
if self.target.func == nil then
return true
end
if self.obj_not_nil and self.target.func == nil then
return true
end
return self.over
end
Timer.__init = __init
Timer.Init = Init
Timer.Update = Update
Timer.Start = Start
Timer.Pause = Pause
Timer.Resume = Resume
Timer.Stop = Stop
Timer.Reset = Reset
Timer.IsOver = IsOver
return Timer;
- Coroutine.lua
--[[
-- 协程模块:对Lua协程conroutine进行扩展,使其具有Unity侧协程的特性
-- 注意:
-- 1、主线程使用coroutine.start启动协程,协程启动以后,首次挂起时主线程继续往下执行,这里和Unity侧表现是一致的
-- 2、协程里可以再次使用coroutine.start启动协程,和在Unity侧协程中使用StartCoroutine表现一致
-- 3、协程里启动子级协程并等待其执行完毕,在Unity侧是yield return StartCoroutine,但是在Lua不需要另外启动协程,直接调用函数即可
-- 4、如果lua侧协程不使用本脚本的扩展函数,则无法实现分帧;lua侧启动协程以后不管协程函数调用栈多深,不管使用多少次本脚本扩展函数,都运行在一个协程
-- 5、使用coroutine.waitforframes(1)来等待一帧,千万不要用coroutine.yield,否则整个协程将永远不被唤醒===>***很重要,除非你在其它地方手动唤醒它
-- 6、子级协同在lua侧等同于普通函数调用,和普通函数一样可在退出函数时带任意返回值,而Unity侧协同不能获取子级协同退出时的返回值
-- 7、理论上任何协同都可以用回调方式去做,但是对于异步操作,回调方式也需要每帧去检测异步操作是否完成,消耗相差不多,而使用协同可以简单很多,清晰很多
-- 8、协程所有等待时间的操作,如coroutine.waitforseconds误差由帧率决定,循环等待时有累积误差,所以最好只是用于分帧,或者等待异步操作
-- 9、yieldstart、yieldreturn、yieldbreak实际上是用lua不对称协程实现对称协同,使用方式和Unity侧协同类似,注意点看相关函数头说明
-- TODO:
-- 1、CS侧做可视化调试器,方便单步查看各个协程运行状态
--]]
-- 协程内部使用定时器实现,定时器是weak表,所以这里必须缓存Action,否则会被GC回收
local action_map = {}
-- action缓存池
local action_pool = {}
-- 用于子级协程yieldreturn时寻找父级协程
local yield_map = {}
-- 协程数据缓存池
local yield_pool = {}
-- 协程缓存池
local co_pool = {}
-- 回收协程
local function __RecycleCoroutine(co)
if not coroutine.status(co) == "suspended" then
error("Try to recycle coroutine not suspended : "..coroutine.status(co))
end
table.insert(co_pool, co)
end
-- 可复用协程
local function __Coroutine(func, ...)
local args = SafePack(...)
while func do
local ret = SafePack(func(SafeUnpack(args)))
__RecycleCoroutine(coroutine.running())
args = SafePack(coroutine.yield(SafeUnpack(ret)))
func = args[1]
table.remove(args, 1)
end
end
-- 获取协程
local function __GetCoroutine()
local co = nil
if table.length(co_pool) > 0 then
co = table.remove(co_pool)
else
co = coroutine.create(__Coroutine)
end
return co
end
-- 回收Action
local function __RecycleAction(action)
action.co = false
action.timer = false
action.func = false
action.args = false
action.result = false
table.insert(action_pool, action)
end
-- 获取Action
local function __GetAction(co, timer, func, args, result)
local action = nil
if table.length(action_pool) > 0 then
action = table.remove(action_pool)
else
action = {false, false, false, false, false}
end
action.co = co and co or false
action.timer = timer and timer or false
action.func = func and func or false
action.args = args and args or false
action.result = result and result or false
return action
end
-- 协程运行在保护模式下,不会抛出异常,所以这里要捕获一下异常
-- 但是可能会遇到调用协程时对象已经被销毁的情况,这种情况应该被当做正常情况
-- 所以这里并不继续抛出异常,而只是输出一下错误日志,不要让客户端当掉
-- 注意:Logger中实际上在调试模式会抛出异常
local function __PResume(co, func, ...)
local resume_ret = nil
if func ~= nil then
resume_ret = SafePack(coroutine.resume(co, func, ...))
else
resume_ret = SafePack(coroutine.resume(co, ...))
end
local flag, msg = resume_ret[1], resume_ret[2]
if not flag then
Logger.LogError(msg.."\n"..debug.traceback(co))
elseif resume_ret.n > 1 then
table.remove(resume_ret, 1)
else
resume_ret = nil
end
return flag, resume_ret
end
-- 启动一个协程:等待协程第一次让出控制权时主函数继续往下执行,这点表现和Unity协程一致
-- 等同于Unity侧的StartCoroutine
-- @func:协程函数体
-- @...:传入协程的可变参数
local function start(func, ...)
local co = __GetCoroutine()
__PResume(co, func, ...)
return co
end
-- 启动一个协程并等待
-- 注意:
-- 1、这里会真正启动一个子级协程,比起在协程中直接函数调用开销稍微大点,但是灵活度很高
-- 2、最大好处就是可以在子级协程中使用yieldreturn返回值给父级协程执行一次某个回调,用于交付数据给父级协程
-- 3、如果子级协程没有结束,父级协程会在执行完回调之后等待一帧再次启动子级协程
-- 4、具体运用参考场景管理(ScenceManager)部分控制加载界面进度条的代码,十分清晰简洁
-- 5、如果不需要callback,即不需要子级协程交付数据,别使用yieldstart,直接使用普通函数调用方式即可
-- 6、回调callback函数体一般处理的是父级协程的逻辑,但是跑在子级协程内,这点要注意,直到yieldbreak父级协程都是挂起的
-- @func:子级协程函数体
-- @callback:子级协程在yieldreturn转移控制权给父级协程时,父级协程跑的回调,这个回调会填入子级协程yieldreturn时的参数
-- @...:传递给子级协程的可变参数
local function yieldstart(func, callback, ...)
local co = coroutine.running() or error ('coroutine.yieldstart must be run in coroutine')
local map = nil
if table.length(yield_pool) > 0 then
map = table.remove(yield_pool)
map.parent = co
map.callback = callback
map.waiting = false
map.over = false
else
map = {parent = co, callback = callback, waiting = false, over = false}
end
local child = __GetCoroutine()
yield_map[child] = map
local flag, resume_ret = __PResume(child, func, ...)
if not flag then
table.insert(yield_pool, map)
yield_map[child] = nil
return nil
elseif map.over then
table.insert(yield_pool, map)
yield_map[child] = nil
if resume_ret == nil then
return nil
else
return SafeUnpack(resume_ret)
end
else
map.waiting = true
local yield_ret = SafePack(coroutine.yield())
table.insert(yield_pool, map)
yield_map[child] = nil
return SafeUnpack(yield_ret)
end
end
-- 子级协程将控制权转移给父级协程,并交付数据给父级协程回调,配合yieldstart使用
-- 注意:
-- 1、与Unity侧协程yield return不同,对子级协程来说yieldreturn一定会等待一帧再往下执行
local function yieldreturn(...)
local co = coroutine.running() or error ("coroutine.yieldreturn must be run in coroutine")
local map = yield_map[co]
local parent = map.parent
-- 没有父级协程,啥都不做
if not map or not parent then
return
end
local callback = map.callback
assert(callback ~= nil, "If you don't need callback, use normal function call instead!!!")
callback(co, ...)
-- 子级协程等待一帧再继续往下执行
return coroutine.waitforframes(1)
end
-- 子级协程在异步回调中交付数据给父级协程回调,配合yieldstart使用
-- 注意:
-- 1、子级协程异步回调并没有运行在子级协程当中,不能使用yieldreturn,实际上不能使用任何协程相关接口,除了start
-- 2、yieldcallback需要传递当前的子级协程,这个可以从异步回调的首个参数获取
-- 3、不会等待一帧,实际上协程中的回调是每帧执行一次的
local function yieldcallback(co, ...)
assert(co ~= nil and type(co) == "thread")
local map = yield_map[co]
-- 没有父级协程,啥都不做
if not map or not map.parent then
return
end
local callback = map.callback
assert(callback ~= nil, "If you don't need callback, use normal function call instead!!!")
callback(co, ...)
end
-- 退出子级协程,将控制权转移给父级协程,并交付数据作为yieldstart返回值,配合yieldstart使用
-- 注意:
-- 1、一定要使用return coroutine.yieldbreak退出===>很重要***
-- 2、不使用coroutine.yieldbreak无法唤醒父级协程
-- 3、不使用return,可能无法正确退出子级协程
local function yieldbreak(...)
local co = coroutine.running() or error ("coroutine.yieldbreak must be run in coroutine")
local map = yield_map[co]
-- 没有父级协程
if not map then
return ...
end
map.over = true
assert(map.parent ~= nil, "What's the fuck!!!")
if not map.waiting then
return ...
else
__PResume(map.parent, nil, ...)
end
end
local function __Action(action, abort, ...)
assert(action.timer)
if not action.func then
abort = true
end
if not abort and action.func then
if action.args and action.args.n > 0 then
abort = (action.func(SafeUnpack(action.args)) == action.result)
else
abort = (action.func() == action.result)
end
end
if abort then
action.timer:Stop()
action_map[action.co] = nil
__PResume(action.co, ...)
__RecycleAction(action)
end
end
-- 等待下次FixedUpdate,并在FixedUpdate执行完毕后resume
-- 等同于Unity侧的yield return new WaitForFixedUpdate
local function waitforfixedupdate()
local co = coroutine.running() or error ("coroutine.waitforfixedupdate must be run in coroutine")
local timer = TimerManager:GetInstance():GetCoFixedTimer()
local action = __GetAction(co, timer)
timer:Init(0, __Action, action, true, true)
timer:Start()
action_map[co] = action
return coroutine.yield()
end
-- 等待帧数,并在Update执行完毕后resume
local function waitforframes(frames)
assert(type(frames) == "number" and frames >= 1 and math.floor(frames) == frames)
local co = coroutine.running() or error ("coroutine.waitforframes must be run in coroutine")
local timer = TimerManager:GetInstance():GetCoTimer()
local action = __GetAction(co, timer)
timer:Init(frames, __Action, action, true, true)
timer:Start()
action_map[co] = action
return coroutine.yield()
end
-- 等待秒数,并在Update执行完毕后resume
-- 等同于Unity侧的yield return new WaitForSeconds
local function waitforseconds(seconds)
assert(type(seconds) == "number" and seconds >= 0)
local co = coroutine.running() or error ("coroutine.waitforsenconds must be run in coroutine")
local timer = TimerManager:GetInstance():GetCoTimer()
local action = __GetAction(co, timer)
timer:Init(seconds, __Action, action, true)
timer:Start()
action_map[co] = action
return coroutine.yield()
end
local function __AsyncOpCheck(co, async_operation, callback)
if callback ~= nil then
callback(co, async_operation.progress)
end
return async_operation.isDone
end
-- 等待异步操作完成,并在Update执行完毕resume
-- 等同于Unity侧的yield return AsyncOperation
-- 注意:yield return WWW也是这种情况之一
-- @async_operation:异步句柄---或者任何带有isDone、progress成员属性的异步对象
-- @callback:每帧回调,传入参数为异步操作进度progress
local function waitforasyncop(async_operation, callback)
assert(async_operation)
local co = coroutine.running() or error ("coroutine.waitforasyncop must be run in coroutine")
local timer = TimerManager:GetInstance():GetCoTimer()
local action = __GetAction(co, timer, __AsyncOpCheck, SafePack(co, async_operation, callback), true)
timer:Init(1, __Action, action, false, true)
timer:Start()
action_map[co] = action
return coroutine.yield()
end
-- 等待条件为真,并在Update执行完毕resume
-- 等同于Unity侧的yield return new WaitUntil
local function waituntil(func, ...)
assert(func)
local co = coroutine.running() or error ("coroutine.waituntil must be run in coroutine")
local timer = TimerManager:GetInstance():GetCoTimer()
local action = __GetAction(co, timer, func, SafePack(...), true)
timer:Init(1, __Action, action, false, true)
timer:Start()
action_map[co] = action
return coroutine.yield()
end
-- 等待条件为假,并在Update执行完毕resume
-- 等同于Unity侧的yield return new WaitWhile
local function waitwhile(func, ...)
assert(func)
local co = coroutine.running() or error ("coroutine.waitwhile must be run in coroutine")
local timer = TimerManager:GetInstance():GetCoTimer()
local action = __GetAction(co, timer, func, SafePack(...), false)
timer:Init(1, __Action, action, false, true)
timer:Start()
action_map[co] = action
return coroutine.yield()
end
-- 等待本帧结束,并在进入下一帧之前resume
-- 等同于Unity侧的yield return new WaitForEndOfFrame
local function waitforendofframe()
local co = coroutine.running() or error ("coroutine.waitforendofframe must be run in coroutine")
local timer = TimerManager:GetInstance():GetCoLateTimer()
local action = __GetAction(co, timer)
timer:Init(0, __Action, action, true, true)
timer:Start()
action_map[co] = action
return coroutine.yield()
end
-- 终止协程等待操作(所有waitXXX接口)
local function stopwaiting(co, ...)
local action = action_map[co]
if action then
__Action(action, true, ...)
end
end
coroutine.start = start
coroutine.yieldstart = yieldstart
coroutine.yieldreturn = yieldreturn
coroutine.yieldcallback = yieldcallback
coroutine.yieldbreak = yieldbreak
coroutine.waitforfixedupdate = waitforfixedupdate
coroutine.waitforframes = waitforframes
coroutine.waitforseconds = waitforseconds
coroutine.waitforasyncop = waitforasyncop
coroutine.waituntil = waituntil
coroutine.waitwhile = waitwhile
coroutine.waitforendofframe = waitforendofframe
coroutine.stopwaiting = stopwaiting
-- 调试用:查看内部状态
if Config.Debug then
return{
action_map = action_map,
action_pool = action_pool,
yield_map = yield_map,
yield_pool = yield_pool,
co_pool = co_pool,
}
end
支付宝捐赠