Skip to content

Instantly share code, notes, and snippets.

@mohiji
Created May 23, 2017 18:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mohiji/9e47a0af518bcaa364e885ae6f6bea0d to your computer and use it in GitHub Desktop.
Save mohiji/9e47a0af518bcaa364e885ae6f6bea0d to your computer and use it in GitHub Desktop.
Coroutine test in LÖVE
-- main.lua
-- This file contains the actual demonstration code. The stuff that implements waits and signals
-- is in wait_support.
wait_support = require("wait_support")
local georgeColor = {0, 255, 0, 255}
local bobColor = {255, 0, 255, 255}
local georgeText = ""
local bobText = ""
function George()
while true do
georgeText = "Hey there, Bob."
wait_support.waitSeconds(2)
wait_support.signal("go-ahead-bob-1")
wait_support.waitSeconds(0.5)
georgeText = ""
wait_support.waitSignal("go-ahead-george-1")
georgeText = "Can't complain. It's been raining. You?"
wait_support.waitSeconds(2)
wait_support.signal("go-ahead-bob-2")
wait_support.waitSeconds(0.5)
georgeText = ""
wait_support.waitSignal("go-ahead-george-2")
georgeText = "You too, Bob."
wait_support.waitSeconds(2)
georgeText = ""
wait_support.waitSeconds(2)
end
end
function Bob()
while true do
wait_support.waitSignal("go-ahead-bob-1")
bobText = "Hi George. How's it going?"
wait_support.waitSeconds(2)
wait_support.signal("go-ahead-george-1")
wait_support.waitSeconds(0.5)
bobText = ""
wait_support.waitSignal("go-ahead-bob-2")
bobText = "Same old, same old."
wait_support.waitSeconds(2)
bobText = "Looking forward to some snow."
wait_support.waitSeconds(2)
bobText = "Well, I best be going. Take care, George."
wait_support.waitSeconds(2)
wait_support.signal("go-ahead-george-2")
wait_support.waitSeconds(0.5)
bobText = ""
end
end
function love.load()
wait_support.runProcess(George)
wait_support.runProcess(Bob)
end
function love.update(dt)
wait_support.wakeUpWaitingThreads(dt)
end
function love.draw()
local georgeTable = {
color1 = georgeColor,
string1 = georgeText
}
local bobTable = {
color1 = bobColor,
string1 = bobText
}
love.graphics.setColor(georgeColor)
love.graphics.printf(georgeText, 40, 200, 200, "left")
love.graphics.setColor(bobColor)
love.graphics.printf(bobText, 40, 400, 200, "right")
end
-- This file implements waitSeconds, waitSignal, signal, and their supporting stuff.
local wait_support = {}
-- This table is indexed by coroutine and simply contains the time at which the coroutine
-- should be woken up.
local WAITING_ON_TIME = {}
-- This table is indexed by signal and contains list of coroutines that are waiting
-- on a given signal
local WAITING_ON_SIGNAL = {}
-- Keep track of how long the game has been running.
local CURRENT_TIME = 0
function wait_support.waitSeconds(seconds)
-- Grab a reference to the current running coroutine.
local co = coroutine.running()
-- If co is nil, that means we're on the main process, which isn't a coroutine and can't yield
assert(co ~= nil, "The main thread cannot wait!")
-- Store the coroutine and its wakeup time in the WAITING_ON_TIME table
local wakeupTime = CURRENT_TIME + seconds
WAITING_ON_TIME[co] = wakeupTime
-- And suspend the process
return coroutine.yield(co)
end
function wait_support.wakeUpWaitingThreads(deltaTime)
-- This function should be called once per game logic update with the amount of time
-- that has passed since it was last called
CURRENT_TIME = CURRENT_TIME + deltaTime
-- First, grab a list of the threads that need to be woken up. They'll need to be removed
-- from the WAITING_ON_TIME table which we don't want to try and do while we're iterating
-- through that table, hence the list.
local threadsToWake = {}
for co, wakeupTime in pairs(WAITING_ON_TIME) do
if wakeupTime < CURRENT_TIME then
table.insert(threadsToWake, co)
end
end
-- Now wake them all up.
for _, co in ipairs(threadsToWake) do
WAITING_ON_TIME[co] = nil -- Setting a field to nil removes it from the table
coroutine.resume(co)
end
end
function wait_support.waitSignal(signalName)
-- Same check as in waitSeconds; the main thread cannot wait
local co = coroutine.running()
assert(co ~= nil, "The main thread cannot wait!")
if WAITING_ON_SIGNAL[signalStr] == nil then
-- If there wasn't already a list for this signal, start a new one.
WAITING_ON_SIGNAL[signalName] = { co }
else
table.insert(WAITING_ON_SIGNAL[signalName], co)
end
return coroutine.yield()
end
function wait_support.signal(signalName)
local threads = WAITING_ON_SIGNAL[signalName]
if threads == nil then return end
WAITING_ON_SIGNAL[signalName] = nil
for _, co in ipairs(threads) do
coroutine.resume(co)
end
end
function wait_support.runProcess(func)
-- This function is just a quick wrapper to start a coroutine.
local co = coroutine.create(func)
return coroutine.resume(co)
end
return wait_support
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment