- Lua Game Development Cookbook
- Mário Ka?uba
- 719字
- 2021-07-16 13:23:09
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.
- Visual Studio 2012 Cookbook
- Reactive Programming with Swift
- PowerCLI Cookbook
- 算法訓練營:提高篇(全彩版)
- Mastering ServiceNow(Second Edition)
- Python編程:從入門到實踐
- BIM概論及Revit精講
- SQL 經典實例
- Java零基礎實戰
- Scratch編程從入門到精通
- Splunk Essentials
- Practical Linux Security Cookbook
- 軟件工程實用教程 (第3版)
- Getting Started with SQL Server 2014 Administration
- Android移動應用設計與開發(第2版):基于Android Studio開發環境