-- 用来实现自动倒计时,并可以做数据绑定,具体用法参考VT_RemainTime.lua local RemainTime = class("RemainTime"); function RemainTime:ctor() -- 当前剩余秒数,每秒更新一次,可绑定 self.Value = 0; -- 总剩余时间(单位秒,外部设置),可绑定 self.RemainTime = 0; -- 上次更新的本地时间 self.LastTime = 0 -- 总共流失了多少时间 self.TotalElapse = 0 -- 开始倒计时的时间(os.time()获取) self.StartTime = 0; -- 计时到0后,回调OnTimeOver(self) self.OnTimeOver = nil; -- 数据绑定列表,key是变量名(Value或RemainTime),value是Binder表 self.BindsByName = {} -- 根据索引排序的绑定列表,key是BindIndex,value是Binder表 self.BindsByIndex = {} -- 绑定索引 self.BindIndex = 0; -- 每隔多久触发一次 self.Interval = 1; -- 定时器速度 self.Speed = 1; -- 暂停状态 self.Pause = false; end function RemainTime:setInterval(interval) if self.Interval ~= interval then self.Interval = interval; if self.TimerID then self:stopTimer(); self:startTimer(); end end end -- 设置加速速度 function RemainTime:setSpeed(speed) self.Speed = speed end -- 设置剩余秒数多少 function RemainTime:setRemainTime(seconds) --print("设置倒计时" , seconds); if type(seconds) == "table" then seconds = seconds:getRemainTime(); end self.RemainTime = seconds; self.Value = seconds; self.StartTime = os.time() self.LastTime = self.StartTime self.TotalElapse = 0 self:triggerBinder("RemainTime"); self:triggerBinder("Value"); -- 开始计时 if self.Value > 0 and next(self.BindsByIndex) ~= nil and self.Pause == false then self:startTimer(); end end function RemainTime:getRemainTime() return self.RemainTime; end function RemainTime:updateTo(target) target.Value = self.Value; target.RemainTime = self.RemainTime; target.StartTime = self.StartTime; target.LastTime = self.LastTime target.TotalElapse = self.TotalElapse target.Speed = self.Speed if target.startTimer and target.Value > 0 and next(target.BindsByIndex) ~= nil and target.Pause == false then target:startTimer() end return target; end; -- 获取一个绑定实例 function RemainTime:getBinder(valueName) local bindTable = self.BindsByName[valueName]; -- 根据名字创建绑定表,一个名字可以绑定多次 if bindTable == nil then bindTable = {}; self.BindsByName[valueName] = bindTable; end self.BindIndex = self.BindIndex + 1 -- 创建单个绑定实例 local binder = { TargetNode = nil; ValueName = valueName; BindIndex = self.BindIndex; OnPropChanged = nil }; self.BindsByIndex[binder.BindIndex] = binder; bindTable[binder.BindIndex] = binder; return binder; end -- 每秒回调一次 function RemainTime:onTimer() local now = os.time() local elapse = (now - self.LastTime) * self.Speed; self.TotalElapse = self.TotalElapse + elapse self.LastTime = now -- 计算剩余时间 self.Value = self.RemainTime - self.TotalElapse; if self.Value <= 0 then self.Value = 0; end --print("计算剩余时间:" , self.Value , self.RemainTime , seconds , now , self.StartTime); -- 触发数据修改通知 self:triggerBinder("Value"); -- 倒计时结束 if self.Value <= 0 then --print("倒计时结束" , self.Value); self:stopTimer(); if self.OnTimeOver then self.OnTimeOver(self); end; end; end -- 触发数据修改通知 function RemainTime:triggerBinder(valueName) local value = self[valueName]; --print("值改变:" , valueName , value); local binders = self.BindsByName[valueName]; if binders then for i , v in pairs(binders) do v.OnPropChanged(valueName , value); end end end -- 开始计时器 function RemainTime:startTimer() if self.Pause then return end if self.TimerID == nil then self.TimerID = cc.Director:getInstance():getScheduler():scheduleScriptFunc(function()self:onTimer()end, self.Interval, false); end end -- 停止计时器 function RemainTime:stopTimer() if self.TimerID then cc.Director:getInstance():getScheduler():unscheduleScriptEntry(self.TimerID); self.TimerID = nil; end end -- 暂停计时器(计时器就不走了) function RemainTime:pause() if self.Pause then return end self:stopTimer() -- 执行一次时间 self:onTimer() self.Pause = true end -- 恢复计时器 function RemainTime:resume() if not self.Pause then return end self.Pause = false -- 如果时间完了就不能开始了 if self.Value <= 0 then print("计时器时间已经流失完了,恢复失败") return end -- 重新设置下时间 self:setRemainTime(self.Value) end -- 实现自动绑定数据的函数 -- @valueName 需要绑定哪个变量名 -- @propertyNameOrFunc , 当添加事件发生时的回调或设置什么属性,回调格式是func(key , value); -- @return 返回绑定索引 function RemainTime:bind(valueName , propertyNameOrFunc , targetNode) local onPropChange; local typeP = type(propertyNameOrFunc); if typeP == "function" then onPropChange = function(key , value) propertyNameOrFunc(self , value); end elseif typeP == "string" then local function onChange(key , value) self[propertyNameOrFunc](self , value); end onPropChange = onChange else error("绑定数据" .. tostring(valueName) .. "时第三个参数错误,必须是属性名或函数" .. tostring(propertyNameOrFunc)) return; end local binder = self:getBinder(valueName); binder.TargetNode = targetNode; binder.OnPropChanged = onPropChange; -- 开始计时 if self.Value > 0 then self:startTimer(); end self:triggerBinder(valueName); return binder.BindIndex; end -- 解除绑定 function RemainTime:unbind(bindIndex) local binder = self.BindsByIndex[bindIndex]; if binder == nil then print("找不到绑定索引" .. tostring(bindIndex)); return; end self.BindsByName[binder.ValueName][bindIndex] = nil; self.BindsByIndex[bindIndex] = nil; -- 没人绑定了,就停止计时器 if next(self.BindsByIndex) == nil then self:stopTimer(); end end return RemainTime;