当前位置: 首页 > 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);
#endif        new LuaResLoader();lua  = new LuaState();lua.Start();LuaBinder.Bind(lua);DelegateFactory.Init();         looper = gameObject.AddComponent<LuaLooper>();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<LuaLooper>();
/*
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
endfunction CoFunc()print('Coroutine started')    for i = 0, 10, 1 doprint(fib(i))                    coroutine.wait(0.1)						end	print("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')
endfunction TestCortinue()	coroutine.start(CoFunc)
endlocal coDelay = nilfunction Delay()local c = 1while true docoroutine.wait(1) print("Count: "..c)c = c + 1end
endfunction StartDelay()coDelay = coroutine.start(Delay)
endfunction 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 = CoTimerlocal 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 then					error(debug.traceback(co, msg))end					elselocal args = {...}local timer = nil		local action = function()												comap[co] = niltimer.func = nillocal flag, msg = resume(co, unpack(args))						table.insert(pool, timer)if not flag then	timer:Stop()														error(debug.traceback(co, msg))						end		endif #pool > 0 thentimer = table.remove(pool)timer:Reset(action, 0, 1)elsetimer = FrameTimer.New(action, 0, 1)endcomap[co] = timertimer:Start()		endreturn co
endfunction coroutine.wait(t, co, ...)local args = {...}co = co or running()		local timer = nillocal action = function()		comap[co] = nil		timer.func = nillocal flag, msg = resume(co, unpack(args))if not flag then	timer:Stop()						error(debug.traceback(co, msg))			returnendendtimer = CoTimer.New(action, t, 1)comap[co] = timer	timer:Start()return yield()
endfunction coroutine.step(t, co, ...)local args = {...}co = co or running()		local timer = nillocal action = function()	comap[co] = nil					timer.func = nillocal flag, msg = resume(co, unpack(args))table.insert(pool, timer)if not flag then	timer:Stop()																			error(debug.traceback(co, msg))return	end		endif #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()
endfunction coroutine.www(www, co)			co = co or running()			local timer = nil			local action = function()				if not www.isDone then		return		end		comap[co] = niltimer:Stop()		timer.func = nillocal flag, msg = resume(co)			table.insert(pool, timer)	if not flag then												error(debug.traceback(co, msg))			return			end				end		if #pool > 0 thentimer = table.remove(pool)timer:Reset(action, 1, -1)else	timer = FrameTimer.New(action, 1, -1)	endcomap[co] = timer	timer:Start()return yield()
endfunction 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 then		if jit.opt then		jit.opt.start(3)				end		print("ver"..jit.version_num.." jit: ", jit.status())print(string.format("os: %s, arch: %s", jit.os, jit.arch))
endif DebugServerIp then  require("mobdebug").start(DebugServerIp)
endrequire "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.dtcms.com/a/486007.html

相关文章:

  • keil5使用STlink下载程序到stm32后不自动运行的解决办法
  • stm32大项目阶段20251015
  • 机器学习四范式(有监督、无监督、强化学习、半监督学习)
  • 源码分析 golang bigcache 高性能无 GC 开销的缓存设计实现
  • 网站开发的工资开发者应用
  • 东莞网站建设优化企业太平洋保险网站
  • transformer-注意力评分函数
  • 破解 Shuffle 阻塞:Spark RDD 宽窄依赖在实时特征工程中的实战与未来
  • TypeScript入门学习
  • 西固网站建设平台12306网站花多少钱做的
  • Linux运维实战:云原生设计与实施DockerK8S(视频教程)
  • Chroma 开源的 AI 应用搜索与检索数据库(即向量数据库)
  • 楼宇自控 DDC 系统 + IBMS 智能化集成系统:构建建筑智慧运营双核心
  • 《深度学习框架核心之争:PyTorch动态图与早期TensorFlow静态图的底层逻辑与实战对比》
  • 固件下printf函数分析
  • 做外贸都得有网站吗秦皇岛网站排名公司
  • AI-Native 能力反思(三):Prompt Engineering 自我提升神器
  • 基于Django+Vue2+MySQL前后端分离的红色故事分享平台
  • LangGraph 工作流全解析:从 Prompt 到智能体编排的革命
  • JAVA算法练习题day42
  • 天津市建设工程备案网站什么是网站的层次
  • 【基础算法】BFS
  • 国家工信部网站备案查询系统公司网址怎么做出来的
  • 做网站都用到哪些软件asp源码打开网站
  • React组件生命周期节点触发时机(组件加载Mount、组件更新Update、组件卸载Unmount)组件挂载
  • 月球矩阵日志:Swift 6.2 主线程隔离抉择(上)
  • 无需 iCloud 在 iPhone 之间传输文本消息
  • Flink受管状态自定义序列化原理深度解析与实践指南
  • Unity Visual Graph粒子系统 Plexus 效果
  • 淘宝里网站建设公司可以吗无经验能做sem专员