天天看點

unity3d支援typescript開發

目錄

  1. unity3d支援typescript開發(一)
  2. unity3d支援typescript開發(二)
  3. unity3d支援typescript開發(三)
  4. unity3d支援typescript開發(四)
  5. unity3d支援typescript開發(五)
  6. 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還是有點遠的.由于時間比較零碎,是以其餘的部分會在有空的時候繼續提供.如果文章中有任何錯誤或者疑問歡迎提出,如果文章對你有幫助也歡迎打賞,謝謝.