最近手上的案子是個麻煩的遊戲,對於遊戲開發來說狀態機(state machine)是很重要的流程控制器,認真研究了一下 Lua 才發現原來它有 Coroutine(協同程序)這個有趣的功能(AS 系列是沒有這種東西的,請原諒我的無知),有興趣搞懂 Coroutine 的朋友可以參考:electronic_blue 的使用 Coroutine 改寫狀態機,它恰恰是以 CoronaSDK 為範本作教學,簡單參考了它的範例程式,打包成了 statemachine.lua 供 CoronaSDK 開發使用。
用法很簡單如同 statemachine.lua 上面寫的範例:
也特別提供了 waiting and continue 功能來做畫面等待與繼續的工作,範例如下:
用法很簡單如同 statemachine.lua 上面寫的範例:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local sm = require("statemachine") | |
local process = sm.new(function(self, time) | |
self:sleep(100) | |
print("hello") | |
self:sleep(100) | |
print("hehe...") | |
self:sleep(100) | |
print("end") | |
end) | |
process:run() |
也特別提供了 waiting and continue 功能來做畫面等待與繼續的工作,範例如下:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local sm = require("statemachine") | |
local process = sm.new(function(self, time) | |
local txt = display.newText( "Press Me", display.contentCenterX, display.contentCenterY, native.systemFont, 32) | |
txt:addEventListener("touch", function(evt) | |
self:continue() | |
end) | |
self:waiting() | |
txt.text = "Hello!" | |
end) | |
process:run() |
statemachine.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
statemachine.lua | |
Copyright (c) 2013 Erin Lin | |
erinylin.blogspot.com | |
Licensed under the MIT license. | |
Usage: | |
local sm = require("statemachine") | |
local process = sm.new(function(self, time) | |
self:sleep(100) | |
print("hello") | |
self:sleep(100) | |
print("hehe...") | |
self:sleep(100) | |
print("end") | |
end) | |
process:run() | |
local process1 = sm.new(function(self, time) | |
local txt = display.newText( "Press Me", display.contentCenterX, display.contentCenterY, native.systemFont, 32) | |
txt:addEventListener("touch", function(evt) | |
self:continue() | |
end) | |
self:waiting() | |
txt.text = "Hello!" | |
self:sleep(200) | |
txt.text = "Bye Bye!" | |
end) | |
process1:run() | |
]]-- | |
local StateMachine = {} | |
local StateMachine_mt = { __index = StateMachine } | |
local coroutine = { | |
yield = coroutine.yield, | |
resume = coroutine.resume, | |
create = coroutine.create, | |
status = coroutine.status | |
} | |
function StateMachine:sleep(msec) | |
self._wakeup = system.getTimer() + msec | |
while self._wakeup > 0 do | |
coroutine.yield() | |
end | |
end | |
function StateMachine:enterFrame(event) | |
if self._wakeup > 0 then | |
if event.time > self._wakeup then | |
self._wakeup = 0 | |
end | |
else | |
local state = coroutine.status(self._co) | |
if state == "suspended" then | |
coroutine.resume(self._co, self) | |
elseif state == "dead" then | |
if self._isLoop then | |
self._co = coroutine.create( self._callback ) | |
else | |
Runtime:removeEventListener("enterFrame", self) | |
self._co = nil | |
end | |
end | |
end | |
end | |
function StateMachine:pause() | |
self._stopTime = system.getTimer() | |
Runtime:removeEventListener("enterFrame", self) | |
end | |
function StateMachine:resume() | |
if self._co then | |
if self._wakeup > 0 then | |
self._wakeup = self._wakeup + system.getTimer() - self._stopTime | |
end | |
Runtime:addEventListener("enterFrame", self) | |
else | |
self:run() | |
end | |
end | |
-- you can loop this. | |
function StateMachine:run(isLoop) | |
self._isLoop = isLoop | |
if not self._co then | |
self._wakeup = 0 | |
self._stopTime = 0 | |
Runtime:addEventListener("enterFrame", self ) | |
self._co = coroutine.create( self._callback ) | |
end | |
end | |
function StateMachine:isRunning() | |
return self._co ~= nil | |
end | |
function StateMachine:destroy() | |
Runtime:removeEventListener("enterFrame", self ) | |
self._callback, self._co, self = nil, nil, nil | |
end | |
function StateMachine:cancel() | |
Runtime:removeEventListener("enterFrame", self ) | |
self._co = nil | |
end | |
function StateMachine:waiting() | |
self._isPass = false | |
while not self._isPass do | |
coroutine.yield() | |
end | |
end | |
function StateMachine:continue() | |
self._isPass = true | |
end | |
local function new(callback) | |
local ds = {} | |
setmetatable(ds, StateMachine_mt) | |
ds._callback = callback | |
ds._wakeup = 0 | |
return ds | |
end | |
return {new=new} |
請問您使用 corona 的開發工具是用哪一套? 謝謝
ReplyDeleteSublime, 你可以參考我前面寫的開發工具篇。=)
ReplyDelete