一.运行工程
本例展示Lua模拟Unity的Coroutine携程的第二种做法

二.C#代码分析
TestCoroutine2.CS
cs
using UnityEngine;
using System.Collections;
using LuaInterface;
//两套协同勿交叉使用,类unity原生,大量使用效率低
public class TestCoroutine2 : LuaClient
{
string script =
@"
function CoExample()
WaitForSeconds(1)
print('WaitForSeconds end time: '.. UnityEngine.Time.time)
WaitForFixedUpdate()
print('WaitForFixedUpdate end frameCount: '..UnityEngine.Time.frameCount)
WaitForEndOfFrame()
print('WaitForEndOfFrame end frameCount: '..UnityEngine.Time.frameCount)
Yield(null)
print('yield null end frameCount: '..UnityEngine.Time.frameCount)
Yield(0)
print('yield(0) end frameCime: '..UnityEngine.Time.frameCount)
local www = UnityEngine.WWW('http://www.baidu.com')
Yield(www)
print('yield(www) end time: '.. UnityEngine.Time.time)
local s = tolua.tolstring(www.bytes)
print(s:sub(1, 128))
print('coroutine over')
end
function TestCo()
StartCoroutine(CoExample)
end
local coDelay = nil
function Delay()
local c = 1
while true do
WaitForSeconds(1)
print('Count: '..c)
c = c + 1
end
end
function StartDelay()
coDelay = StartCoroutine(Delay)
end
function StopDelay()
StopCoroutine(coDelay)
coDelay = nil
end
";
protected override LuaFileUtils InitLoader()
{
return new LuaResLoader();
}
protected override void OnLoadFinished()
{
base.OnLoadFinished();
luaState.DoString(script, "TestCoroutine2.cs");
LuaFunction func = luaState.GetFunction("TestCo");
func.Call();
func.Dispose();
func = null;
}
//屏蔽,例子不需要运行
protected override void CallMain() { }
bool beStart = false;
string tips = null;
void Start()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived += ShowTips;
#else
Application.RegisterLogCallback(ShowTips);
#endif
}
void ShowTips(string msg, string stackTrace, LogType type)
{
tips += msg;
tips += "\r\n";
}
new void OnApplicationQuit()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived -= ShowTips;
#else
Application.RegisterLogCallback(null);
#endif
base.OnApplicationQuit();
}
void OnGUI()
{
GUI.Label(new Rect(Screen.width / 2 - 300, Screen.height / 2 - 200, 600, 400), tips);
if (GUI.Button(new Rect(50, 50, 120, 45), "Start Counter"))
{
if (!beStart)
{
beStart = true;
tips = "";
LuaFunction func = luaState.GetFunction("StartDelay");
func.Call();
func.Dispose();
}
}
else if (GUI.Button(new Rect(50, 150, 120, 45), "Stop Counter"))
{
if (beStart)
{
beStart = false;
LuaFunction func = luaState.GetFunction("StopDelay");
func.Call();
func.Dispose();
}
}
}
}
2.1 LuaClient.CS
首先看第六行TestCoroutine2 继承自 LuaClient
cs
public class TestCoroutine2 : LuaClient
LuaClient的159-177行可以看出其初始化时创建了LuaState对象,故TestCoroutine2中没有LuaState对象的创建,可以直接使用父类的
cs
protected void Init()
{
InitLoader();
luaState = new LuaState();
OpenLibs();
luaState.LuaSetTop(0);
Bind();
LoadLuaFiles();
}
protected void Awake()
{
Instance = this;
Init();
#if UNITY_5_4_OR_NEWER
SceneManager.sceneLoaded += OnSceneLoaded;
#endif
}
再来看TestCoroutine2.CS的64-66行,执行Lua方法TestCo
cs
luaState.DoString(script, "TestCoroutine2.cs");
LuaFunction func = luaState.GetFunction("TestCo");
func.Call();
TestCoroutine2.CS的29-31行TestCo调用StartCoroutine
Lua
function TestCo()
StartCoroutine(CoExample)
end
2.2 LuaCoroutine.CS
全局搜索function StartCoroutine可以看到其定义位于文件LuaCoroutine.CS中

在DoString处加入断点,可以看到其由LuaClient的Awake中间接调用

三.Lua代码分析
从StartCoroutine的Lua实现来看,其用的是Lua语言自身的coroutine
Lua
function StartCoroutine(func)
local co = coroutine.create(func)
local flag, msg = coroutine.resume(co)
if not flag then
msg = debug.traceback(co, msg)
error(msg)
end
return co
end