Ok, so imagine the following scenario:
You want to ask a question of the user and blocking the returning script without actually blocking the engine. Now, I know this can probably be done with coroutines in Lua but im not sure exactly how to structure my code.
Can anyone help?
EDIT: Ok this seems to work, I seem to have solved my own problem but its a little messy i think
co = coroutine.create(function()
logmsg("run")
QuestionScreen:Ask(co, "Yes", "No") -- this pops up a GUI asking a question
coroutine.yield() -- this waits until the GUI input function gets its answer but does not block the engine.
if QuestionScreen.Selected == 1 then
PlayerAvatar:Say("Lol")
else
PlayerAvatar:Say("Not Lol")
end
end)
coroutine.resume(co)
Here's what I would try, to make it a little neater:-
Have a self-yielding version of QuestionScreen:Ask() that expects to be called in the context of the coroutine to be suspended:
function QuestionScreen:AskAsync(...)
self:Ask(coroutine.running(), ...)
coroutine.yield()
return self.Selected
end
Create a utility function for running a block of code in a coroutine:
function async(fn)
coroutine.resume( coroutine.create(fn) )
end
An example of using these things together:
async(function()
logmsg("run")
if QuestionScreen:AskAsync("Yes", "No") == 1 then
PlayerAvatar:Say("Lol")
else
PlayerAvatar:Say("Not Lol")
end
end)
Also if you'd like to make it a bit more robust by sanity-checking that self-yielding functions like QuestionScreen:AskAsync() are called from the context of an async(function() ... end) "block", you could modify the async() system a bit like this:
-- weak table for identifying async coroutines without leaking memory
local async_coros = setmetatable({}, {__mode='k'})
function async(fn)
local co = coroutine.create(fn)
async_coros[co] = true
coroutine.resume(co)
end
-- if called in the context of an async block, return the associated coroutine
-- if not running in an async block, throw an error
function inasync()
local co = coroutine.running()
assert(co and async_coros[co], 'async function called from non-async context')
return co
end
...and then, use inasync() instead of coroutine.running() in QuestionScreen:AskAsync().
Excellent, thats exactly what i wanted.
I wanted a way to get all the coroutine stuff away from my game logic and this does that nicely, thanks.
(Edit: Oops. Ignore!)