目錄
- unity3d支持typescript開發(一)
- unity3d支持typescript開發(二)
- unity3d支持typescript開發(三)
- unity3d支持typescript開發(四)
- unity3d支持typescript開發(五)
- unity3d支持typescript開發(六)
前言
由於之前的工作是在游戲公司做unity框架,該框架使用的是lua+unity的方案,而最近頻繁接觸typescript后,就有了想要在unity框架內支持typescript的想法.
早期的unity是支持javascript后面簡寫為js
的,但是后來被unity拋棄了,其實讓unity支持typescript后面簡寫為ts
跟支持lua是很相似的,只需要找到一個可以在.net環境下執行js的解釋器即可,而js可以通過編譯ts來獲得,那么即可支持ts了.
那么此次我們來完成一個示例,首先unity啟動自會后會加載一個prefab,然后加載對應路徑的js代碼並調用onStart方法,該js方法內會調用console.log,而該函數會轉而調用unity內的Debug.Log方法.
.net庫
https://github.com/sebastienros/jint 是比較符合當前條件的.net庫, 但是該庫只提供了基礎的js環境, 而該環境中並不包含console對象.
初始化jint
首先在canvas下添加一個腳本,在該腳本內初始化jint,當Awake方法被觸發的時候,加載prefab, C#代碼如下:
class DemoCanvas : MonoBehaviour
{
private readonly Engine m_Engine = new Engine();
private void Awake()
{
var prefab = Resources.Load<Component>("demo/Index");
Instantiate(prefab, this.transform);
}
}
執行js腳本
由於上文中我們將Jint的初始化代碼放在了Canvas內,因此js腳本的加載執行就不能參考canvas的流程來了,因為Instantiate的時候Awake會被觸發如果這時候要調用Jint.Engine的話則需要將該字段開放,這樣循環引用並不好,因此此處改為在prefab內開放一個方法用於初始化, C#代碼如下:
// js
console.log('hello world');
// C#
class DemoView : MonoBehaviour
{
public void EvalScript(Engine engine)
{
var js = Resources.Load<TextAsset>("demo/index");
engine.Execute(js.text);
}
}
// DemoCanvas
public void Awake()
{
var prefab = Resources.Load<Component>("demo/Index");
Instantiate(prefab, this.transform).GetComponent<DemoView>().EvalScript(this.m_Engine);
}
運行以后出現了錯誤,這是由於Jint並沒有提供console這個對象,因此需要自己擴展一個console對象.
console對象
閱讀Jint的源碼內我們可以發現,Jint的對象需要繼承自ObjectInstance,然后調用FastAddProperty給該對象添加一個屬性,該方法的定義如下:
public void FastAddProperty(string name, JsValue value, bool writable, bool enumerable, bool configurable)
除了JsValue以外,其他的參數字面上跟js是一致的,這里就不解釋了.由於console.log是一個函數,因此這里JsValue需要使用ClrFunctionInstance,ClrFunctionInstance的定義如下:
public sealed class ClrFunctionInstance : FunctionInstance
{
public ClrFunctionInstance(Engine engine, Func<JsValue, JsValue[], JsValue> func);
public ClrFunctionInstance(Engine engine, Func<JsValue, JsValue[], JsValue> func, int length);
public override JsValue Call(JsValue thisObject, JsValue[] arguments);
}
構造函數中有兩個,其中一個包含了一個int length
的參數,因為console.log是不限定參數個數的,因此我們使用另外一個不包含length的構造函數,C#代碼如下:
class ConsoleInstance : ObjectInstance
{
public ConsoleInstance(Engine engine) : base(engine)
{
this.Prototype = engine.Object.Prototype;
this.FastAddProperty("log", new ClrFunctionInstance(this.Engine, Log), true, false, true);
}
public JsValue Log(JsValue thisObject, JsValue[] arguments)
{
Debug.Log(arguments[0].ToString());
return JsValue.Null;
}
}
// DemoCanvas
public void Awake()
{
var console = new ConsoleInstance(this.m_Engine)
{
Prototype = this.m_Engine.Object.PrototypeObject
};
this.m_Engine.SetValue("console", console);
// 略
}
這里為了簡化log方法內參數的判斷,代碼改為只對第一個值進行ToString的處理.
結尾
到了這里我們就已經完成了unity支持執行js腳本了,但是離支持ts還是有點遠的.由於時間比較零碎,因此其余的部分會在有空的時候繼續提供.如果文章中有任何錯誤或者疑問歡迎提出,如果文章對你有幫助也歡迎打賞,謝謝.