unity3d支持typescript开发
目录
- 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还是有点远的.由于时间比较零碎,因此其余的部分会在有空的时候继续提供.如果文章中有任何错误或者疑问欢迎提出,如果文章对你有帮助也欢迎打赏,谢谢.