官术网_书友最值得收藏!

Using timers

LuaSDL offers support for timer objects. The problematic part is the use of timers. The LibSDL library uses callback functions to call event functions. These callbacks run in another thread and the na?ve approach, where you put the Lua function in the position of callback function, would lead to Lua state corruption. There is a better way to accomplish this by using the internal LuaSDL callback function that invokes a special user event.

Timers aren't very precise and they are mostly used in GUI updates. If you need more precision, you'll need to use High Precision Event Timer (HPET), which is out of the scope of this book.

Getting ready

Each timer object uses a user-defined event that contains unique timer function identifiers represented by integer values. LuaSDL offers a slightly modified version of the SDL.SDL_AddTimer function, where it accepts two parameters instead of three. The first parameter is an interval value in milliseconds. The second is the user-defined event object.

How to do it…

The first thing you'll need to do is to define your user-defined event. You can use the SDL.SDL_Event_local function to create one:

local timerEvent = SDL.SDL_Event_local()

The next thing you'll need to do is to set the event code specific for a timer object. You can then create a timer object with the SDL.SDL_AddTimer function. This function returns an internal timer ID, which you can use with the SDL.SDL_RemoveTimer function to stop the timer.

So far, you've created a user-defined event generator that will generate events at a specified interval. To make this useful, you can define your user event handler with the following code:

[SDL.SDL_USEREVENT] = function(_event)
  local event = _event.user
  if event.code > 0 then
    timerCallback(event.code)
  end
end

You can use the event code to specify what callback function will be called.

How it works…

After you create the timer object with SDL.SDL_AddTimer, LuaSDL calls the real SDL_AddTimer function with its own callback function that will periodically push the event you specified in the second function argument into the event queue. Fortunately, event handling in LuaSDL is one of the few things that is thread safe. Timer callback functions don't run strictly in specified intervals. This is because there are platform-specific limitations and, what's more, callback functions only push events into the event queue. Your application can process timer events much later.

There's more…

To make timer handling more efficient, you can define a function that will take two arguments. The first one is the interval and the second is a function or a closure.

This approach uses central table timers with all the timer objects and the user event handler will always try to query the timer function from the timers table, as shown in the following code:

local timers = {}
local timerID = 0

-- Each call to createTimer function will create a new timer object.
-- Interval argument expects a time in millisecond units
-- Supplied function in the second argument will be called repeatedly
local function createTimer(interval, fn)
  assert(type(interval)=='number' and type(fn)=='function')
  local timerObj = {}
  -- Unique timerID number generator with simple incremental counting
  timerID = timerID+1
  -- timerEvent will be used to contain timerID user value
  local timerEvent = SDL.SDL_Event_local()
  -- Store a reference for timerEvent object
  -- so it won't be prematurely garbage collected
  timerObj.event = timerEvent
  timerObj.call = fn
  timerEvent.type = SDL.SDL_USEREVENT
     timerEvent.user.code = timerID
  -- Create LuaSDL timer object
  local timer = SDL.SDL_AddTimer(interval, timerEvent)
  timerObj.timer = timer
  -- Destroys current timer object
  timerObj.remove = function()
    SDL.SDL_RemoveTimer(timer)
    timers[timerID] = nil
  end
  timers[timerID] = timerObj
end

There remains one small modification in the user event handler, which is as follows:

[SDL.SDL_USEREVENT] = function(raw_event)
  local event = raw_event.user
  if event.code > 0 then
    local timer = timers[event.code]
    if timer and type(timer.call)=="function" then
      timer.call()
    end
  end
end

The last thing you need to do is to clean up all timers before exiting your application. This is caused by the fact that timer objects from LuaSDL aren't automatically garbage collected. You can achieve this with the following simple iteration:

for _, timer in pairs(timers) do
  timer.remove()
end

The remove function will stop the timer and destroy the timer object. Without this step, you'd be relying on the automatic cleanup functions of the operating system, which is never a good idea. In the worst case, it could cause a memory leak.

主站蜘蛛池模板: 遂溪县| 佳木斯市| 黑河市| 柯坪县| 郴州市| 永靖县| 中宁县| 杨浦区| 商水县| 八宿县| 循化| 汝南县| 大兴区| 徐州市| 会昌县| 海盐县| 曲沃县| 达拉特旗| 静乐县| 青海省| 绵阳市| 诏安县| 藁城市| 伊金霍洛旗| 沧源| 西和县| 津市市| 通河县| 酒泉市| 汕尾市| 沛县| 柳州市| 东港市| 新和县| 武冈市| 论坛| 行唐县| 登封市| 内丘县| 新泰市| 安吉县|