Таймеры от BMD

doter.ua

Продвинутый
17 Авг 2014
280
5
ТАЙМЕРЫ от BMD

Код:
--[[
 -- A timer running every second that starts immediately on the next frame, respects pauses
 Timers:CreateTimer(function()
   print ("Hello. I'm running immediately and then every second thereafter.")
   return 1.0
  end
 )
 -- A timer running every second that starts 5 seconds in the future, respects pauses
 Timers:CreateTimer(5, function()
   print ("Hello. I'm running 5 seconds after you called me and then every second thereafter.")
   return 1.0
  end
 )
 -- 10 second delayed, run once using gametime (respect pauses)
 Timers:CreateTimer({
  endTime = 10, -- when this timer should first execute, you can omit this if you want it to run first on the next frame
  callback = function()
   print ("Hello. I'm running 10 seconds after when I was started.")
  end
 })
 -- 10 second delayed, run once regardless of pauses
 Timers:CreateTimer({
  useGameTime = false,
  endTime = 10, -- when this timer should first execute, you can omit this if you want it to run first on the next frame
  callback = function()
   print ("Hello. I'm running 10 seconds after I was started even if someone paused the game.")
  end
 })
 -- A timer running every second that starts after 2 minutes regardless of pauses
 Timers:CreateTimer("uniqueTimerString3", {
  useGameTime = false,
  endTime = 120,
  callback = function()
   print ("Hello. I'm running after 2 minutes and then every second thereafter.")
   return 1
  end
 })
 -- A timer using the old style to repeat every second starting 5 seconds ahead
 Timers:CreateTimer("uniqueTimerString3", {
  useOldStyle = true,
  endTime = GameRules:GetGameTime() + 5,
  callback = function()
   print ("Hello. I'm running after 5 seconds and then every second thereafter.")
   return GameRules:GetGameTime() + 1
  end
 })
]]



TIMERS_THINK = 0.01

if Timers == nil then
 print ( '[Timers] creating Timers' )
 Timers = {}
 Timers.__index = Timers
end

function Timers:new( o )
 o = o or {}
 setmetatable( o, Timers )
 return o
end

function Timers:start()
 Timers = self
 self.timers = {}
 
 local ent = Entities:CreateByClassname("info_target") -- Entities:FindByClassname(nil, 'CWorld')
 ent:SetThink("Think", self, "timers", TIMERS_THINK)
end

function Timers:Think()
 if GameRules:State_Get() >= DOTA_GAMERULES_STATE_POST_GAME then
  return
 end

 -- Track game time, since the dt passed in to think is actually wall-clock time not simulation time.
 local now = GameRules:GetGameTime()

 -- Process timers
 for k,v in pairs(Timers.timers) do
  local bUseGameTime = true
  if v.useGameTime ~= nil and v.useGameTime == false then
   bUseGameTime = false
  end
  local bOldStyle = false
  if v.useOldStyle ~= nil and v.useOldStyle == true then
   bOldStyle = true
  end

  local now = GameRules:GetGameTime()
  if not bUseGameTime then
   now = Time()
  end

  if v.endTime == nil then
   v.endTime = now
  end
  -- Check if the timer has finished
  if now >= v.endTime then
   -- Remove from timers list
   Timers.timers[k] = nil
   
   -- Run the callback
   local status, nextCall = pcall(v.callback, GameRules:GetGameModeEntity(), v)

   -- Make sure it worked
   if status then
    -- Check if it needs to loop
    if nextCall then
     -- Change its end time

     if bOldStyle then
      v.endTime = v.endTime + nextCall - now
     else
      v.endTime = v.endTime + nextCall
     end

     Timers.timers[k] = v
    end

    -- Update timer data
    --self:UpdateTimerData()
   else
    -- Nope, handle the error
    Timers:HandleEventError('Timer', k, nextCall)
   end
  end
 end

 return TIMERS_THINK
end

function Timers:HandleEventError(name, event, err)
 print(err)

 -- Ensure we have data
 name = tostring(name or 'unknown')
 event = tostring(event or 'unknown')
 err = tostring(err or 'unknown')

 -- Tell everyone there was an error
 --Say(nil, name .. ' threw an error on event '..event, false)
 --Say(nil, err, false)

 -- Prevent loop arounds
 if not self.errorHandled then
  -- Store that we handled an error
  self.errorHandled = true
 end
end

function Timers:CreateTimer(name, args)
 if type(name) == "function" then
  args = {callback = name}
  name = DoUniqueString("timer")
 elseif type(name) == "table" then
  args = name
  name = DoUniqueString("timer")
 elseif type(name) == "number" then
  args = {endTime = name, callback = args}
  name = DoUniqueString("timer")
 end
 if not args.callback then
  print("Invalid timer created: "..name)
  return
 end


 local now = GameRules:GetGameTime()
 if args.useGameTime ~= nil and args.useGameTime == false then
  now = Time()
 end

 if args.endTime == nil then
  args.endTime = now
 elseif args.useOldStyle == nil or args.useOldStyle == false then
  args.endTime = now + args.endTime
 end

 Timers.timers[name] = args 

 return name
end

function Timers:RemoveTimer(name)
 Timers.timers[name] = nil
end

function Timers:RemoveTimers(killAll)
 local timers = {}

 if not killAll then
  for k,v in pairs(Timers.timers) do
   if v.persist then
    timers[k] = v
   end
  end
 end

 Timers.timers = timers
end

Timers:start()

Первое, что бросается в глаза - куча примеров (типа вместо документации). Их действительно куча, и даже немного сбивают столку: какой юзать, а чем этот отличается от другого и т. д. Сама "библиотека" представляет из себя набор функций, которые можно использовать вызвав и передав нужные параметры. Как стандартный print('текст').
Но если стандартный принт подключен в стандартной Луа, то таймеры написал чувак с ником BMD (гамбургер) и чтобы использовать таймеры нужно их подключить вручную, или просто закинуть все содержимое в файл, где собираемся использовать, но это быдлокод.
Итак подключаем:
[list type=decimal]
[li]Скачиваем луа файл по ссылке выше. [/li]
[li]Кидаем в папку с скриптами (там, где аддон_гейм_мод.луа)[/li]
[li]В аддоне_гейм_луа подключаем: require('имя_файла_без_расширения') т.е. timers.lua будет как 'timers'. Подключать нужно выше места, где будем юзать таймеры, что логично. Например в init функции[/li]
[li]Создать таймер.[/li]
[/list]
Я, лично, использовал два типа таймеров: который выполняется раз в "n" сек, и второй - ждет "m" сек и начинает выполнятся раз в "n" сек. таймер как Thinker, но лучше, да и вызывать можно где угодно, а не только в инит. Чтобы остановить(удалить) таймер передаем return nil

Первый тип
Timers:CreateTimer(function()
--действия
return 1.0 -- 1.0 Время следующего запуска в сек, nil - остановиться.
end )


Второй тип
Timers:CreateTimer(5, function() -- Такой же как и первый, но ждет 5 сек перед первым запуском.
--действия
return 1.0 -- 1.0 Время следующего запуска в сек, nil - остановиться.
end )

Обычно в блоке "действия" добавляют проверку на успешность выполнения какой-либо цели, и в случае успеха return nill Время можно задавать в дробных: return 0.5 Есть другие типы таймеров, например: игнорирующие паузы или наоборот ожидающие вместе с паузами и .т.д.

Сам файл (возможно будет обновляться)
 
Последнее редактирование модератором:
Реклама: