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

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.

主站蜘蛛池模板: 丰宁| 许昌市| 当涂县| 罗定市| 双流县| 兴仁县| 团风县| 遂川县| 克什克腾旗| 朔州市| 抚顺县| 陇南市| 德格县| 将乐县| 平远县| 中西区| 吴川市| 五原县| 布拖县| 江城| 南丰县| 林周县| 洞头县| 东乡县| 原阳县| 南乐县| 华亭县| 柏乡县| 于都县| 鸡西市| 睢宁县| 鹰潭市| 曲阜市| 泽州县| 鄂温| 榕江县| 东源县| 恩平市| 广元市| 梅州市| 井冈山市|