既然已經出現了一些意見,詢問如何實現wait
功能,這將使deft_code
的例子的工作,我決定寫一個可能的實現。總的想法是我們有一個調度程序和一系列協程,調度程序決定何時在控制wait
調用後放棄對協程的控制。這是可取的,因爲它使得異步代碼易讀並易於推理。
這只是協程的一種可能的用法,它們是一個更一般的抽象工具,可用於許多不同的目的(例如編寫迭代器和生成器,編寫有狀態的流處理對象(例如,解析器),實現異常和延續等)。
第一:調度定義:
local function make_scheduler()
local script_container = {}
return {
continue_script = function(frame, script_thread)
if script_container[frame] == nil then
script_container[frame] = {}
end
table.insert(script_container[frame],script_thread)
end,
run = function(frame_number, game_control)
if script_container[frame_number] ~= nil then
local i = 1
--recheck length every time, to allow coroutine to resume on
--the same frame
local scripts = script_container[frame_number]
while i <= #scripts do
local success, msg =
coroutine.resume(scripts[i], game_control)
if not success then error(msg) end
i = i + 1
end
end
end
}
end
現在,初始化世界:
local fps = 60
local frame_number = 1
local scheduler = make_scheduler()
scheduler.continue_script(frame_number, coroutine.create(function(game_control)
while true do
--instead of passing game_control as a parameter, we could
--have equivalently put these values in _ENV.
game_control.wait(game_control.seconds(5))
game_control.start_eruption_volcano()
game_control.wait(game_control.frames(10))
s = game_control.play("rumble_sound")
game_control.wait(game_control.end_of(s))
game_control.start_camera_shake()
-- more stuff
game_control.wait(game_control.minutes(2))
end
end))
的(虛擬)接口的遊戲:
local game_control = {
seconds = function(num)
return math.floor(num*fps)
end,
minutes = function(num)
return math.floor(num*fps*60)
end,
frames = function(num) return num end,
end_of = function(sound)
return sound.start+sound.duration-frame_number
end,
wait = function(frames_to_wait_for)
scheduler.continue_script(
frame_number+math.floor(frames_to_wait_for),
coroutine.running())
coroutine.yield()
end,
start_eruption_volcano = function()
--obviously in a real game, this could
--affect some datastructure in a non-immediate way
print(frame_number..": The volcano is erupting, BOOM!")
end,
start_camera_shake = function()
print(frame_number..": SHAKY!")
end,
play = function(soundname)
print(frame_number..": Playing: "..soundname)
return {name = soundname, start = frame_number, duration = 30}
end
}
而且遊戲圈:
while true do
scheduler.run(frame_number,game_control)
frame_number = frame_number+1
end
協程不是線程。它們是線程的,因爲它們是獨立的執行環境,但是你的程序是調度程序,並且它們不是搶佔式的。我會添加一個完整的答案,但我的Lua是生鏽的,所以我不能提供任何代碼示例... – 2011-02-26 17:09:26