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

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.

主站蜘蛛池模板: 台中市| 肃南| 苏州市| 临沧市| 仁寿县| 定结县| 临沧市| 金山区| 麦盖提县| 商南县| 沙洋县| 柏乡县| 江孜县| 阿荣旗| 沙河市| 福州市| 锡林浩特市| 东山县| 芷江| 郓城县| 龙胜| 井陉县| 南靖县| 滕州市| 宁陕县| 邢台市| 霍邱县| 井冈山市| 资中县| 城固县| 汤原县| 逊克县| 湘潭市| 曲阳县| 台南市| 海晏县| 绥德县| 寿光市| 明溪县| 高清| 乌什县|