溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

用C#寫(xiě)的協(xié)程轉(zhuǎn)換成JavaScript后無(wú)法正常工作怎么辦

發(fā)布時(shí)間:2021-12-18 10:25:22 來(lái)源:億速云 閱讀:151 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“用C#寫(xiě)的協(xié)程轉(zhuǎn)換成JavaScript后無(wú)法正常工作怎么辦”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“用C#寫(xiě)的協(xié)程轉(zhuǎn)換成JavaScript后無(wú)法正常工作怎么辦”吧!

先說(shuō)結(jié)論吧:用C#寫(xiě)的協(xié)程轉(zhuǎn)換成 JavaScript 后,無(wú)法正常工作,必須要手動(dòng)修改一點(diǎn)點(diǎn)代碼。

以下是 TestCoroutine.cs 代碼:

1 [JsType(JsMode.Clr,"../../../StreamingAssets/JavaScript/SharpKitGenerated/JSBinding/Samples/Coroutine/TestCoroutine.javascript")]
 2 public class TestCoroutine : MonoBehaviour {
 3 
 4     // Use this for initialization
 5     void Start () 
 6     {
 7         StartCoroutine(DoTest());
 8     }
 9     
10     // Update is called once per frame
11     void Update () 
12     {
13     
14     }
15     void LateUpdate()
16     {
17         jsimp.Coroutine.UpdateMonoBehaviourCoroutine(this);
18     }
19     IEnumerator WaitForCangJingKong()
20     {
21         yield return new WaitForSeconds(2f);
22     }
23     IEnumerator DoTest()
24     {
25         // test null
26         Debug.Log(1);
27         yield return null;
28 
29         // test WaitForSeconds
30         Debug.Log(2);
31         yield return new WaitForSeconds(1f);
32 
33         // test WWW
34         WWW www = new WWW("file://" + Application.dataPath + "/JSBinding/Samples/Coroutine/CoroutineReadme.txt");
35         yield return www;
36         Debug.Log("Text from WWW: " + www.text);
37 
38         // test another coroutine
39         yield return StartCoroutine(WaitForCangJingKong());
40         Debug.Log("Wait for CangJingKong finished!");
41     }  
42 }

這是 SharpKit 編譯后的代碼:

1 if (typeof(JsTypes) == "undefined")
 2     var JsTypes = [];
 3 var TestCoroutine = {
 4     fullname: "TestCoroutine",
 5     baseTypeName: "UnityEngine.MonoBehaviour",
 6     assemblyName: "SharpKitProj",
 7     Kind: "Class",
 8     definition: {
 9         ctor: function (){
10             UnityEngine.MonoBehaviour.ctor.call(this);
11         },
12         Start: function (){
13             this.StartCoroutine$$IEnumerator(this.DoTest());
14         },
15         Update: function (){
16         },
17         LateUpdate: function (){
18             jsimp.Coroutine.UpdateMonoBehaviourCoroutine(this);
19         },
20         WaitForCangJingKong: function (){
21             var $yield = [];
22             $yield.push(new UnityEngine.WaitForSeconds.ctor(2));
23             return $yield;
24         },
25         DoTest: function (){
26             var $yield = [];
27             UnityEngine.Debug.Log$$Object(1);
28             $yield.push(null);
29             UnityEngine.Debug.Log$$Object(2);
30             $yield.push(new UnityEngine.WaitForSeconds.ctor(1));
31             var www = new UnityEngine.WWW.ctor$$String("file://" + UnityEngine.Application.get_dataPath() + "/JSBinding/Samples/Coroutine/CoroutineReadme.txt");
32             $yield.push(www);
33             UnityEngine.Debug.Log$$Object("Text from WWW: " + www.get_text());
34             $yield.push(this.StartCoroutine$$IEnumerator(this.WaitForCangJingKong()));
35             UnityEngine.Debug.Log$$Object("Wait for CangJingKong finished!");
36             return $yield;
37         }
38     }
39 };
40 JsTypes.push(TestCoroutine);

注意看 DoTest 函數(shù)和 WaitForCangJingKong 函數(shù),他們都是協(xié)程函數(shù)。SharpKit 對(duì)其中的 yield 代碼翻譯成一個(gè) $yield 數(shù)組,每一個(gè) yield 指令都加到 $yield 數(shù)組中。

這樣使得我們無(wú)法與 JavaScript 的 yield 對(duì)接。這就是為什么協(xié)程編譯成 JavaScript 代碼后無(wú)法直接使用的原因。

目前,需要做點(diǎn)小修改就可以運(yùn)行了,以下是修改過(guò)的 JavaScript 文件:

1 if (typeof(JsTypes) == "undefined")
 2     var JsTypes = [];
 3 var TestCoroutine = {
 4     fullname: "TestCoroutine",
 5     baseTypeName: "UnityEngine.MonoBehaviour",
 6     assemblyName: "SharpKitProj",
 7     Kind: "Class",
 8     definition: {
 9         ctor: function (){
10             UnityEngine.MonoBehaviour.ctor.call(this);
11         },
12         Start: function (){
13             this.StartCoroutine$$IEnumerator(this.DoTest());
14         },
15         Update: function (){
16         },
17         LateUpdate: function (){
18             jsimp.Coroutine.UpdateMonoBehaviourCoroutine(this);
19         },
20         WaitForCangJingKong: function* (){
21 
22             yield (new UnityEngine.WaitForSeconds.ctor(2));
23 
24         },
25         DoTest: function* (){
26 
27             UnityEngine.Debug.Log$$Object(1);
28             yield (null);
29             UnityEngine.Debug.Log$$Object(2);
30             yield (new UnityEngine.WaitForSeconds.ctor(1));
31             var www = new UnityEngine.WWW.ctor$$String("file://" + UnityEngine.Application.get_dataPath() + "/JSBinding/Samples/Coroutine/CoroutineReadme.txt");
32             yield (www);
33             UnityEngine.Debug.Log$$Object("Text from WWW: " + www.get_text());
34             yield (this.StartCoroutine$$IEnumerator(this.WaitForCangJingKong()));
35             UnityEngine.Debug.Log$$Object("Wait for CangJingKong finished!");
36 
37         }
38     }
39 };
40 JsTypes.push(TestCoroutine);

需要修改的有:

  1. 協(xié)程函數(shù)改用 function* 定義

  2. 刪除 $yield 數(shù)組的定義以及協(xié)程函數(shù)最后的返回

  3. 將 $yield.push 替換為 yield 。

===================================================

2015/07/13 22:18 更新,目前已經(jīng)把這個(gè)替換工作做到菜單了,菜單是 JSB | Correct JavaScript Yield code

這個(gè)菜單會(huì)嘗試替換所有在 JSBindingSetting.jsDir 目錄下的所有 JavaScript 文件。你只需要在編譯 SharpKit 工程后運(yùn)行一下這個(gè)菜單即可,如果有錯(cuò)誤會(huì)給出提示,如果沒(méi)錯(cuò),代碼應(yīng)該可以正常使用了!

目前這個(gè)方案算是比較完美了。

用C#寫(xiě)的協(xié)程轉(zhuǎn)換成JavaScript后無(wú)法正常工作怎么辦

下面講一講原理。

當(dāng)我們?cè)?C# 中使用 MonoBehaviour.StartCoroutine 函數(shù)時(shí),傳遞給他代表協(xié)程函數(shù)的 IEnumerator(后面簡(jiǎn)稱(chēng) IE)。之后是由 Unity 內(nèi)部決定何時(shí)調(diào)用 IE.MoveNext()。而這部分的源代碼我們是無(wú)法得到的。

在 JavaScript 端寫(xiě)了一個(gè)模擬 Unity 功能的協(xié)程管理器。文件是:

StreamingAssets/JavaScript/Manual/UnityEngine_MonoBehaviour.javascript

(后面簡(jiǎn)稱(chēng) B)。

這里順便提一下,當(dāng)你導(dǎo)出 MonoBehaviour 類(lèi)時(shí),會(huì)產(chǎn)生

StreamingAssets/JavaScript/Generated/UnityEngine_MonoBehaviour.javascript

文件,簡(jiǎn)稱(chēng)A。B 和 A 的關(guān)系是,在includes.javascript 中,包含順序是先 A 后 B,B重寫(xiě)了一些 A 的函數(shù),并增加了一些內(nèi)部函數(shù)。目前重寫(xiě)的函數(shù)只有 StartCoroutine$$IEnumerator 和 StartCoroutine$$String。增加的函數(shù)有 $UpdateAllCoroutines,$updateCoroutine等等,這些就是協(xié)程管理器的內(nèi)容。以下貼出代碼(可能不是最新的):

1 _jstype = undefined;
  2 for (var i = 0; i < JsTypes.length; i++) {
  3     if (JsTypes[i].fullname == "UnityEngine.MonoBehaviour") {
  4         _jstype = JsTypes[i];
  5         break;
  6     }
  7 }
  8 
  9 if (_jstype) {
 10     _jstype.definition.StartCoroutine$$String = function(a0/*String*/) { 
 11         if (this[a0]) 
 12         {
 13             var fiber = this[a0].call(this);
 14             return this.$AddCoroutine(fiber);
 15         }
 16     }
 17     _jstype.definition.StartCoroutine$$IEnumerator = function(a0/*IEnumerator*/) { 
 18         return this.$AddCoroutine(a0);
 19     }
 20 
 21     //
 22     // Coroutine Scheduler
 23     // 
 24     // REFERENCE FROM
 25     // 
 26     // Coroutine Scheduler:
 27     // http://wiki.unity3d.com/index.php/CoroutineScheduler
 28     //
 29     // JavaScript yield documents:
 30     // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield
 31     // 
 32 
 33     // fiber 類(lèi)似于 C# 的 IEnumerator
 34     _jstype.definition.$AddCoroutine = function (fiber) {
 35         var coroutineNode = {
 36             $__CN: true,  // mark this is a coroutine node
 37             prev: undefined,
 38             next: undefined,
 39             fiber: fiber,
 40             finished: false,
 41 
 42             waitForFrames: 0,          // yield null
 43             waitForSeconds: undefined, // WaitForSeconds
 44             www: undefined,            // WWW
 45             waitForCoroutine: undefined, // Coroutine
 46         };
 47 
 48         if (this.$first) {
 49             coroutineNode.next = this.$first;
 50             this.$first.prev = coroutineNode;
 51         };
 52 
 53         this.$first = coroutineNode;
 54         // NOTE
 55         // return coroutine node itself!
 56         return coroutineNode;
 57     }
 58 
 59     // this method is called from LateUpdate
 60     _jstype.definition.$UpdateAllCoroutines = function (elapsed) {
 61         // cn is short for Coroutine Node
 62         var cn = this.$first;
 63         while (cn != undefined) {
 64             // store next coroutineNode before it is removed from the list
 65             var next = cn.next;
 66             var update = false;
 67 
 68             if (cn.waitForFrames > 0) {
 69                 cn.waitForFrames--;
 70                 if (cn.waitForFrames <= 0) {
 71                     waitForFrames = 0;
 72                     this.$UpdateCoroutine(cn);
 73                 }
 74             }
 75             else if (cn.waitForSeconds) {
 76                 if (cn.waitForSeconds.get_finished(elapsed)) {
 77                     cn.waitForSeconds = undefined;
 78                     this.$UpdateCoroutine(cn);
 79                 }
 80             }
 81             else if (cn.www) {
 82                 if (cn.www.get_isDone()) {
 83                     cn.www = undefined;
 84                     this.$UpdateCoroutine(cn);
 85                 }
 86             }
 87             else if (cn.waitForCoroutine) {
 88                 if (cn.waitForCoroutine.finished == true) {
 89                     cn.waitForCoroutine = undefined;
 90                     this.$UpdateCoroutine(cn);
 91                 }  
 92             }
 93             else {
 94                 this.$UpdateCoroutine(cn);
 95             }
 96             cn = next;
 97         }
 98     }
 99 
100     _jstype.definition.$UpdateCoroutine = function (cn) { // cn is short for Coroutine Node
101         var fiber = cn.fiber;
102         var obj = fiber.next();
103         if (!obj.done) {
104             var yieldCommand = obj.value;
105             // UnityEngine.Debug.Log$$Object(JSON.stringify(yieldCommand));
106             if (yieldCommand == null) {
107                 cn.waitForFrames = 1;
108             }
109             else {
110                 if (yieldCommand instanceof UnityEngine.WaitForSeconds.ctor) {
111                     cn.waitForSeconds = yieldCommand;
112                 } 
113                 else if (yieldCommand instanceof UnityEngine.WWW.ctor) {
114                     cn.www = yieldCommand;
115                 }
116                 else if (yieldCommand.$__CN === true/*yieldCommand.toString() == "[object Generator]"*/) {
117                     cn.waitForCoroutine = yieldCommand;
118                 }
119                 else {
120                     throw "Unexpected coroutine yield type: " + yieldCommand.GetType();
121                 }
122             }
123         } 
124         else {
125             // UnityEngine.Debug.Log$$Object("cn.finished = true;");
126             cn.finished = true;
127             this.$RemoveCoroutine(cn);
128         }
129     }
130 
131     _jstype.definition.$RemoveCoroutine = function (cn) { // cn is short for Coroutine Node
132         if (this.$first == cn) {
133             this.$first = cn.next;
134         } 
135         else {
136             if (cn.next != undefined) {
137                 cn.prev.next = cn.next;
138                 cn.next.prev = cn.prev;
139             }
140             else if (cn.prev) {
141                 cn.prev.next = undefined;
142             }
143         }
144         cn.prev = undefined;
145         cn.next = undefined;
146     }
147 }

目前支持的 yield return 后面可接的類(lèi)型有:

  1. yield return null; // 下一幀調(diào)用 MoveNext()

  2. yield return new WWW(...); // WWW

  3. yield return new WaitForSeconds(...); // 等待一定時(shí)間

  4. yield return new StartCoroutine(...); // 串連另一個(gè)協(xié)程

 C# 協(xié)程和 JavaScript 協(xié)程有一個(gè)區(qū)別:C#是協(xié)程初始就調(diào)用了 MoveNext(),JavaScript 需要初始調(diào)用 next() 才能和 C# 匹配(現(xiàn)在沒(méi)有調(diào)用,因?yàn)橐粠臅r(shí)間也挺快的,效果差不多一樣)。

另外,看前面的 C# 代碼有這樣的代碼:

1 void LateUpdate()
2 {
3      jsimp.Coroutine.UpdateMonoBehaviourCoroutine(this);
4 }


現(xiàn)在因?yàn)槲覀冏约阂芾韰f(xié)程,所以需要有一個(gè) Update 入口。如果想讓 JavaScript 協(xié)程正常工作,必須在某個(gè)地方調(diào)用協(xié)程管理器的 Update?,F(xiàn)在我是把他放在 LateUpdate 函數(shù)中,如果你想換地方,也是可以的。

在 C# 中,jsimp.Coroutine.UpdateMonoBehaviourCoroutine 函數(shù)并不做任何事情,只有當(dāng)運(yùn)行 JavaScript 版本時(shí),才有做事情。JavaScript 的實(shí)現(xiàn)是在這個(gè)文件中:

StreamingAssets/JavaScript/JSImp/Coroutine.javascript

1 if (typeof(JsTypes) == "undefined")
 2     var JsTypes = [];
 3 var jsimp$Coroutine = {
 4     fullname: "jsimp.Coroutine",
 5     baseTypeName: "System.Object",
 6     staticDefinition: {
 7         UpdateMonoBehaviourCoroutine: function (mb){
 8             mb.$UpdateAllCoroutines(UnityEngine.Time.get_deltaTime());
 9         }
10     },
11     assemblyName: "SharpKitProj",
12     Kind: "Class",
13     definition: {
14         ctor: function (){
15             System.Object.ctor.call(this);
16         }
17     }
18 };
19 
20 // replace old Coroutine
21 jsb_ReplaceOrPushJsType(jsimp$Coroutine);

這個(gè)文件同樣在 includes.javascript 中進(jìn)行了包含。

看第8行,調(diào)用了 $UpdateAllCoroutines 函數(shù)更新協(xié)程管理器。

對(duì)于 WaitForSeconds 類(lèi),C#中并沒(méi)有暴露任何接口。我們無(wú)法判斷一個(gè) WaitForSeconds 是否時(shí)間已到。所以我又自定義了這個(gè)類(lèi),來(lái)達(dá)到這個(gè)目的。

文件是:StreamingAssets/JavaScript/Manual/UnityEngine_WaitForSeconds.javascript

1 _jstype = undefined;
 2 for (var i = 0; i < JsTypes.length; i++) {
 3     if (JsTypes[i].fullname == "UnityEngine.WaitForSeconds") {
 4         _jstype = JsTypes[i];
 5         break;
 6     }
 7 }
 8 
 9 if (_jstype) {
10 
11     _jstype.definition.ctor = function(a0) { 
12         this.$totalTime = a0;
13         this.$elapsedTime = 0;
14         this.$finished = false;
15     }
16 
17     _jstype.definition.get_finished = function(elapsed) { 
18         if (!this.$finished) {
19             this.$elapsedTime += elapsed;
20             if (this.$elapsedTime >= this.$totalTime) {
21                 this.$finished = true;
22             }        
23         }
24         return this.$finished;
25     }
26 }

這個(gè)文件也很簡(jiǎn)單,只是記錄初始時(shí)的時(shí)間,后面更新時(shí)時(shí)間進(jìn)行遞增。get_finished() 函數(shù)被協(xié)程管理器用于判斷時(shí)間是否已到。

到此,相信大家對(duì)“用C#寫(xiě)的協(xié)程轉(zhuǎn)換成JavaScript后無(wú)法正常工作怎么辦”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI