协程在unity中是一个很常用的方法,我们可以利用协程使代码看起来更连贯,易于理解。xlua在示例6中提供了一个协程的示例。
local util = require 'xlua.util' local gameobject = CS.UnityEngine.GameObject('Coroutine_Runner') CS.UnityEngine.Object.DontDestroyOnLoad(gameobject) local cs_coroutine_runner = gameobject:AddComponent(typeof(CS.Coroutine_Runner)) local function async_yield_return(to_yield, cb) cs_coroutine_runner:YieldAndCallback(to_yield, cb) end return { yield_return = util.async_to_sync(async_yield_return) } local util = require 'xlua.util' local yield_return = (require 'cs_coroutine').yield_return local co = coroutine.create(function() print('coroutine start!') local s = os.time() yield_return(CS.UnityEngine.WaitForSeconds(3)) print('wait interval:', os.time() - s) local www = CS.UnityEngine.WWW('http://www.qq.com') yield_return(www) if not www.error then print(www.bytes) else print('error:', www.error) end end) assert(coroutine.resume(co))利用这个示例我们可以实现协程的一些功能,比如服务器列表获取,资源下载等。但是,随着项目的推进,我们发现,这个协程和我们在unity中使用的协程是不一样的,我们无法中断它。相信很多人都遇到了这个问题,为了解决这个问题,我们需要换一种思路来实现。 在前面的设计中,我们将c#端的LuaBehaviour注入到了lua端,这以为着我们可以直接利用这个注入变量调用c#端的StartCoroutine函数,能调用到这个函数,问题就直接解决了。 但是,进阶这会发现好像并不能运行,这是因为Lua端的函数仅仅是个普通函数,而协程StartCoroutine要求的函数是要IEnumerator,这意味着我们需要构造出一个IEnumerator来,在官方文档《hotfix.md》里,有一节是“Unity协程”
通过util.cs_generator可以用一个function模拟一个IEnumerator,在里头用coroutine.yield,就类似C#里头的yield return。比如下面的C#代码和对应的hotfix代码是等同效果的
~~~csharp [XLua.Hotfix] public class HotFixSubClass : MonoBehaviour { IEnumerator Start() { while (true) { yield return new WaitForSeconds(3); Debug.Log("Wait for 3 seconds"); } } } ~~~ ~~~csharp luaenv.DoString(@" local util = require 'xlua.util' xlua.hotfix(CS.HotFixSubClass,{ Start = function(self) return util.cs_generator(function() while true do coroutine.yield(CS.UnityEngine.WaitForSeconds(3)) print('Wait for 3 seconds') end end end; }) "); ~~~至此,我们可以构造出IEnumerator,然后调用MonoBehaviour 的StartCoroutine函数来实现unity侧特性的协程,这种协程是可以通过StopCoroutine来中断的。
QQ交流群:517539056,欢迎大家加入一起交流
