当前位置: 首页 > news >正文

实用指南:toLua[六] Examples 05_LuaCoroutine分析

一.运行工程

本例展示Lua模拟Unity的Coroutine携程

二.C#代码分析

using UnityEngine;
using System;
using System.Collections;
using LuaInterface;
//例子5和6展示的两套协同系统勿交叉使用,此为推荐方案
public class TestCoroutine : MonoBehaviour
{public TextAsset luaFile = null;private LuaState lua = null;private LuaLooper looper = null;void Awake (){
#if UNITY_5 || UNITY_2017 || UNITY_2018Application.logMessageReceived += ShowTips;
#elseApplication.RegisterLogCallback(ShowTips);
#endifnew LuaResLoader();lua  = new LuaState();lua.Start();LuaBinder.Bind(lua);DelegateFactory.Init();looper = gameObject.AddComponent();looper.luaState = lua;lua.DoString(luaFile.text, "TestLuaCoroutine.lua");LuaFunction f = lua.GetFunction("TestCortinue");f.Call();f.Dispose();f = null;}void OnApplicationQuit(){looper.Destroy();lua.Dispose();lua = null;
#if UNITY_5 || UNITY_2017 || UNITY_2018Application.logMessageReceived -= ShowTips;
#elseApplication.RegisterLogCallback(null);
#endif}string tips = null;void ShowTips(string msg, string stackTrace, LogType type){tips += msg;tips += "\r\n";}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")){tips = null;LuaFunction func = lua.GetFunction("StartDelay");func.Call();func.Dispose();}else if (GUI.Button(new Rect(50, 150, 120, 45), "Stop Counter")){LuaFunction func = lua.GetFunction("StopDelay");func.Call();func.Dispose();}else if (GUI.Button(new Rect(50, 250, 120, 45), "GC")){lua.DoString("collectgarbage('collect')", "TestCoroutine.cs");Resources.UnloadUnusedAssets();}}
}

2.1 DoString执行文件的方式

首先来看第九行:

public TextAsset luaFile = null;

TextAsset类可以获取文件的文本内容;用TextAsset.text可以访问文件的文本

因此第28行可以用DoString来执行TestLuaCoroutine.lua文件

lua.DoString(luaFile.text, "TestLuaCoroutine.lua");

故本例演示了除LuaState:DoFile(string fileName)和LuaState:Require(string fileName)之外执行Lua文件的第三种方式

Unity手册的解释:

文本资源的一个特性就在于它可用于存储二进制数据。通过为文件提供扩展名 .bytes,即可将其作为文本资源加载,并可通过 bytes 属性来访问数据

这解释了TestLuaCoroutine文件为什么以.bytes为后缀名

参考:

文本资源

2.2 LuaLooper类

第25行给对象加了脚本组件LuaLooper

looper = gameObject.AddComponent();
/*
Copyright (c) 2015-2017 topameng(topameng@qq.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
using System;
using UnityEngine;
using LuaInterface;
public class LuaLooper : MonoBehaviour
{public LuaBeatEvent UpdateEvent{get;private set;}public LuaBeatEvent LateUpdateEvent{get;private set;}public LuaBeatEvent FixedUpdateEvent{get;private set;}public LuaState luaState = null;void Start(){try{UpdateEvent = GetEvent("UpdateBeat");LateUpdateEvent = GetEvent("LateUpdateBeat");FixedUpdateEvent = GetEvent("FixedUpdateBeat");}catch (Exception e){Destroy(this);throw e;}}LuaBeatEvent GetEvent(string name){LuaTable table = luaState.GetTable(name);if (table == null){throw new LuaException(string.Format("Lua table {0} not exists", name));}LuaBeatEvent e = new LuaBeatEvent(table);table.Dispose();table = null;return e;}void ThrowException(){string error = luaState.LuaToString(-1);luaState.LuaPop(2);throw new LuaException(error, LuaException.GetLastError());}void Update(){
#if UNITY_EDITORif (luaState == null){return;}
#endifif (luaState.LuaUpdate(Time.deltaTime, Time.unscaledDeltaTime) != 0){ThrowException();}luaState.LuaPop(1);luaState.Collect();
#if UNITY_EDITORluaState.CheckTop();
#endif}void LateUpdate(){
#if UNITY_EDITORif (luaState == null){return;}
#endifif (luaState.LuaLateUpdate() != 0){ThrowException();}luaState.LuaPop(1);}void FixedUpdate(){
#if UNITY_EDITORif (luaState == null){return;}
#endifif (luaState.LuaFixedUpdate(Time.fixedDeltaTime) != 0){ThrowException();}luaState.LuaPop(1);}public void Destroy(){if (luaState != null){if (UpdateEvent != null){UpdateEvent.Dispose();UpdateEvent = null;}if (LateUpdateEvent != null){LateUpdateEvent.Dispose();LateUpdateEvent = null;}if (FixedUpdateEvent != null){FixedUpdateEvent.Dispose();FixedUpdateEvent = null;}luaState = null;}}void OnDestroy(){if (luaState != null){Destroy();}}
}

LuaLooper的作用是驱动协程的运行,这里暂不作展开

三.Lua代码分析

3.1 TestLuaCoroutine.lua.bytes

function fib(n)local a, b = 0, 1while n > 0 doa, b = b, a + bn = n - 1endreturn a
end
function CoFunc()print('Coroutine started')for i = 0, 10, 1 doprint(fib(i))coroutine.wait(0.1)endprint("current frameCount: "..Time.frameCount)coroutine.step()print("yield frameCount: "..Time.frameCount)local www = UnityEngine.WWW("http://www.baidu.com")coroutine.www(www)local s = tolua.tolstring(www.bytes)print(s:sub(1, 128))print('Coroutine ended')
end
function TestCortinue()coroutine.start(CoFunc)
end
local coDelay = nil
function Delay()local c = 1while true docoroutine.wait(1)print("Count: "..c)c = c + 1end
end
function StartDelay()coDelay = coroutine.start(Delay)
end
function StopDelay()coroutine.stop(coDelay)
end

* fib函数负责计算一个斐那波契n  <br>

* coroutine.start 启动一个lua协同  <br>

* coroutine.wait 协同中等待一段时间,单位:秒  <br>

* coroutine.step 协同中等待一帧.  <br>

* coroutine.www 等待一个WWW完成. <br>

* tolua.tolstring 转换byte数组为lua字符串缓冲 <br>

* coroutine.stop 停止一个正在lua将要执行的协同 <br>

TestLuaCoroutine中全部围绕者全局模块coroutine中函数的使用,接下来看coroutine模块

3.2 coroutine.lua

local create = coroutine.create
local running = coroutine.running
local resume = coroutine.resume
local yield = coroutine.yield
local error = error
local unpack = unpack
local debug = debug
local FrameTimer = FrameTimer
local CoTimer = CoTimer
local comap = {}
local pool = {}
setmetatable(comap, {__mode = "kv"})
function coroutine.start(f, ...)local co = create(f)if running() == nil thenlocal flag, msg = resume(co, ...)if not flag thenerror(debug.traceback(co, msg))endelselocal args = {...}local timer = nillocal action = function()comap[co] = niltimer.func = nillocal flag, msg = resume(co, unpack(args))table.insert(pool, timer)if not flag thentimer:Stop()error(debug.traceback(co, msg))endendif #pool > 0 thentimer = table.remove(pool)timer:Reset(action, 0, 1)elsetimer = FrameTimer.New(action, 0, 1)endcomap[co] = timertimer:Start()endreturn co
end
function coroutine.wait(t, co, ...)local args = {...}co = co or running()local timer = nillocal action = function()comap[co] = niltimer.func = nillocal flag, msg = resume(co, unpack(args))if not flag thentimer:Stop()error(debug.traceback(co, msg))returnendendtimer = CoTimer.New(action, t, 1)comap[co] = timertimer:Start()return yield()
end
function coroutine.step(t, co, ...)local args = {...}co = co or running()local timer = nillocal action = function()comap[co] = niltimer.func = nillocal flag, msg = resume(co, unpack(args))table.insert(pool, timer)if not flag thentimer:Stop()error(debug.traceback(co, msg))returnendendif #pool > 0 thentimer = table.remove(pool)timer:Reset(action, t or 1, 1)elsetimer = FrameTimer.New(action, t or 1, 1)endcomap[co] = timertimer:Start()return yield()
end
function coroutine.www(www, co)co = co or running()local timer = nillocal action = function()if not www.isDone thenreturnendcomap[co] = niltimer:Stop()timer.func = nillocal flag, msg = resume(co)table.insert(pool, timer)if not flag thenerror(debug.traceback(co, msg))returnendendif #pool > 0 thentimer = table.remove(pool)timer:Reset(action, 1, -1)elsetimer = FrameTimer.New(action, 1, -1)endcomap[co] = timertimer:Start()return yield()
end
function coroutine.stop(co)local timer = comap[co]if timer ~= nil thencomap[co] = niltimer:Stop()end
end

哪里导入了coroutine模块呢,全局搜索coroutine"可以看到是tolua.lua的require

3.3 tolua.lua

if jit thenif jit.opt thenjit.opt.start(3)endprint("ver"..jit.version_num.." jit: ", jit.status())print(string.format("os: %s, arch: %s", jit.os, jit.arch))
end
if DebugServerIp thenrequire("mobdebug").start(DebugServerIp)
end
require "misc.functions"
Mathf		= require "UnityEngine.Mathf"
Vector3 	= require "UnityEngine.Vector3"
Quaternion	= require "UnityEngine.Quaternion"
Vector2		= require "UnityEngine.Vector2"
Vector4		= require "UnityEngine.Vector4"
Color		= require "UnityEngine.Color"
Ray			= require "UnityEngine.Ray"
Bounds		= require "UnityEngine.Bounds"
RaycastHit	= require "UnityEngine.RaycastHit"
Touch		= require "UnityEngine.Touch"
LayerMask	= require "UnityEngine.LayerMask"
Plane		= require "UnityEngine.Plane"
Time		= reimport "UnityEngine.Time"
list		= require "list"
utf8		= require "misc.utf8"
require "event"
require "typeof"
require "slot"
require "System.Timer"
require "System.coroutine"
require "System.ValueType"
require "System.Reflection.BindingFlags"

可以看到tolua.lua对同级目录包括子目录(LuaFramework\ToLua\Lua)下多个lua文件进行require

3.4 tolua库的导入

通过搜索tolua.lua可以看到其执行来自在LuaState

Tip:lua文件的执行如果搜索名称没搜到需要加.lua后缀名一起搜索

LuaState.cs:

        void OpenBaseLuaLibs(){DoFile("tolua.lua");            //tolua table名字已经存在了,不能用requireLuaUnityLibs.OpenLuaLibs(L);}

四.小结

至此,该携程example所涉及代码及其先后执行逻辑有了整体的把握和理解,具体coroutine的实现先没有深究的必要,等用到时再回来看即可

http://www.jsqmd.com/news/39285/

相关文章:

  • 唤醒手腕2025年最新钉钉开放强大的平台钉钉机器人stream搭建部署详细教程(更新中)
  • 2025开源能源管理系统标杆:MyEMS 特性解析、社区生态与全场景落地实践
  • 电脑往小米手机里快速传输文件方法
  • 2025年涡街流量计制造厂权威推荐榜单:防爆式超声流量计/孔板流量计/电磁流量计源头厂家精选
  • 告别人工干预!C# 轻量级上位机自动联动 MES 与视觉检测
  • 2025 年 11 月数控滚齿机床厂家推荐排行榜,高速滚齿机,小微齿轮加工,车滚齿复合机床,双主轴数控车滚齿机床公司推荐
  • react 表单管理
  • 2025年拆迁补偿安置口碑推荐榜单:十大专业律所综合评测
  • jenkins构建序号自定义显示
  • 2025 年 11 月连接器厂家推荐排行榜,圆形/M12/M8/防水/水密/重载/传感器/工业/RJ45/以太网连接器公司精选
  • 2025年石岛红光板源头厂家综合评测:石岛红石材/中国黑石材/五莲灰石材源头厂家精选
  • 2025 年 11 月滚珠花键厂家推荐排行榜:圆筒形滚珠花键,法兰型滚珠花键,新型滚珠花键公司推荐
  • 2FSK 调制指数 、相关系数 、 频谱特性
  • 2025 年 11 月靶材厂家推荐排行榜,溅射/磁控溅射/旋转靶材,ITO/半导体/光学镀膜,陶瓷/金属/钛/铝/铜/钨/钼/钽/硅/合金/稀土靶材公司推荐
  • 2、JDBC快速入门
  • 2025 年 11 月高考文化课集训/艺考文化课集训机构推荐排行榜,全日制集训,封闭式管理,重点高中师资,冲刺提分保障!
  • 2025 年 11 月滚珠花键厂家推荐排行榜,圆筒形滚珠花键,法兰型滚珠花键,新型滚珠花键公司推荐,专业选型与高效传动解决方案
  • Qwen Code CLI - Windows 使用
  • [电调]AM32电调调参系列 —— Motor KV参数分析
  • 【Android】【面试】Handler/Looper 相关的知识点和面试常见问题 - 指南
  • 2025年AI数字人获客公司权威推荐榜单:AI公域获客/AI矩阵获客/AI全域获客源头公司精选
  • 模式识别与机器学习课程笔记(3):统计决策中的经典学习手段
  • 11/13
  • 剪映高级感口播字幕预设220M850款轻量合集,拖拽生成商业级动态文字(Win_Mac通用)
  • linux 云主机 pip 安装配置 letsencrypt certbot 为多个域名生成免费 https 证书实录 - Leone
  • 手动清除Ubuntu系统中的内存缓存的步骤
  • VMware ESXi 8.0U3g 集成 RTL8111 / RTL8125 / RTL8126 / RTL8127 网卡驱动定制版
  • VMware ESXi 9.0.1.0 集成 RTL8111 / RTL8125 / RTL8126 / RTL8127 网卡驱动定制版
  • 2025年市面上最佳商标注册服务商Top 5排名与深度评测
  • 2025年商标注册服务商综合评测:五大权威机构深度解析