用协程手动控制基于Lua的两种框架:Codea和Love2D的流程
- 作者: FreeBlues
- 修订版本: 1.00
- 最新链接: https://my.oschina.net/freeblues/blog/1181350
问题来源
最近在 Codea
官网社区看到有人提问如何在 Codea
中实现暂停, 这个帖子 Triggering the pause function Codea has _ FIXED wrote some Lua code
在 Codea 中通过宿主 Objective-C 来控制
最有效的办法当然是通过修改 Lua
的宿主语言 C
来挂起整个虚拟机, 具体方法如下:
在 Codea
导出的 XCode
项目中打开包含 StandaloneViewController
的 .m
文件, 然后修改这个:
StandaloneViewController *cc=self.viewController
把视图控制器保存到变量 cc
中, 那么暂停只需执行如下语句
cc.paused=YES;
恢复只需执行如下语句:
cc.paused=NO;
这应该是一种比较彻底的解决方法, 不过显然无法在 Lua
中来执行, 在 Lua
中它只能暂停, 无法恢复.
在 Codea 中通过 debug 函数来控制
也有人提出用利用 debug
函数的钩子来实现, 代码如下:
function setup()
x=10
y=400
xv=1
yv=1
cnt=0
sec=10
debug.sethook(loop,"l")
end
function loop()
while pause do
ct=os.time()
if ct>st+sec then
pause=false
end
end
end
function draw()
background(40, 40, 50)
fill(255)
text("tap screen to pause for "..sec.." seconds.",WIDTH/2,HEIGHT/2)
x=x+xv
if x>WIDTH or x<0 then
xv=xv*-1
end
y=y+yv
if y>HEIGHT or y<0 then
yv=yv*-1
end
ellipse(x,y,20)
cnt=cnt+1
text(cnt,WIDTH/2,HEIGHT-50)
end
function touched(t)
if t.state==BEGAN then
st=os.time()
pause=true
end
end
这种办法可以在 Codea
内暂停/恢复, 唯一的问题是没办法精确控制, 只能用定时器.
在 Codea 中通过协程来控制
我想到的就是用协程来控制流程, 代码如下:
function setup()
pause = false
-- Create a new coroutine for the function f
co = coroutine.create(f)
box = { x = 10, y = 10,
width = 20, height = 20,
fillColor = color(24, 28, 202, 255) }
-- Here we can not use tween.
-- t = tween(10, box, {x = 1000, y = 1000})
end
-- Put all your draw code in f
function f()
while not pause do
background()
fontSize(40)
fill(0,255,0)
text(os.time(),WIDTH/2,HEIGHT/2)
fill(box.fillColor)
box.x, box.y = box.x+1,box.y+1
rect(box.x,box.y,box.width,box.height)
coroutine.yield()
end
end
function draw()
if not pause then
coroutine.resume(co)
end
end
function touched(t)
-- Click left screen to pause, click right screen to resume
if t.state == BEGAN and t.x >=WIDTH/2 then
pause = false
elseif t.state == BEGAN and t.x <WIDTH/2 then
pause = true
end
end
用协程的优点是可以精确地控制流程, 缺点是所有的地方都要考虑到, 另外一个问题就是可能带来性能损失.
在 Love2D 中通过协程来控制
上面的代码稍作修改就可以用在 Love2D
中, 修改后的代码如下:
function love.load()
canvas = love.graphics.newCanvas(800, 600)
love.graphics.setBackgroundColor(0, 0, 0)
pause = false
-- Create a new coroutine for the function f
co = coroutine.create(f)
box = { x = 10, y = 10, width = 20, height = 20}
end
function f()
while not pause do
--love.graphics.setCanvas(canvas)
love.graphics.setBlendMode("alpha")
love.graphics.setColor(255, 255, 0)
love.graphics.print(os.time(), 300,400)
love.graphics.setColor(0, 255, 0)
box.x, box.y = box.x+1,box.y+1
love.graphics.rectangle("fill", box.x, box.y, box.width, box.height)
--love.graphics.setCanvas()
love.graphics.setBlendMode("alpha")
--love.graphics.draw(canvas)
coroutine.yield()
end
end
function love.draw()
if not pause then
coroutine.resume(co)
end
end
function love.update(delta)
if love.keyboard.isDown("p") then
pause = true
elseif love.keyboard.isDown("s") then
pause = false
end
end
唯一的问题就是每当暂停时, 屏幕就不显示任何内容了, 这种情况显然是因为我对 Love2D
的处理机制理解存在一些小问题, 有时间了再慢慢分析.