以 NGUI 的 UIEventListener 为例:

有一个类:

 1 using SharpKit.JavaScript;
2 using UnityEngine;
3 using System.Collections;
4
5 [JsType(JsMode.Clr,"../StreamingAssets/JavaScript/SharpKitGenerated/z_temp/test0610.javascript")]
6 public class test0610 : MonoBehaviour {
7 public UIButton btn;
8
9 void Start ()
10 {
11 // 在此注册回调
12 UIEventListener.Get(btn.gameObject).onClick = this.OnClick; // (*)
13 }
14
15 void OnClick(GameObject go)
16 {
17 Debug.Log("onclick ");
18 }
19 }

这个类有一个 public UIButton btn;  变量,可以在 Inspector 里赋值。我们用这个类来响应 btn 的点击事件。重点就是第12行。

生成的JS如下:

 1 if (typeof(JsTypes) == "undefined")
2 var JsTypes = [];
3 var test0610 = {
4 fullname: "test0610",
5 baseTypeName: "UnityEngine.MonoBehaviour",
6 assemblyName: "SharpKitProj",
7 Kind: "Class",
8 definition: {
9 ctor: function (){
10 this.btn = null;
11 UnityEngine.MonoBehaviour.ctor.call(this);
12 },
13 Start: function (){
14 UIEventListener.Get(this.btn.get_gameObject()).onClick = $CreateDelegate(this, this.OnClick); // (*)
15 },
16 Update: function (){
17 },
18 OnClick: function (go){
19 UnityEngine.Debug.Log$$Object("onclick ");
20 }
21 }
22 };
23 JsTypes.push(test0610);

看 JS代码 第14行,将 onClick 赋值为 $CreateDelegate 的返回值

$CreateDelegate 的作用是返回一个函数,具体可以看 jsclr.javascript 文件里这个函数的定义。这里不讨论这个函数的实现细节,只要知道他返回一个函数就可以了。这个函数传到 C# 后就变成一个ID。

当然,如果要让这段JS可以正常执行,当然要将 UIEventListener 配置到 JSBindingSettings.classes 数组让他导出,来看一下 onClick 这个字段的C#代码:

 1 public static UIEventListener.VoidDelegate UIEventListener_onClick_GetDelegate_member2_arg0(CSRepresentedObject objFunction)
2 {
3 if (objFunction == null || objFunction.jsObjID == 0)
4 {
5 return null;
6 }
7 UIEventListener.VoidDelegate action = (go) =>
8 {
9 JSMgr.vCall.CallJSFunctionValue(0, objFunction.jsObjID, go);
10 };
11 return action;
12 }
13 static void UIEventListener_onClick(JSVCall vc)
14 {
15 if (vc.bGet) {
16 UIEventListener _this = (UIEventListener)vc.csObj;
17 var result = _this.onClick;
18 JSMgr.vCall.datax.setObject((int)JSApi.SetType.Rval, result);
19 }
20 else {
21 UIEventListener _this = (UIEventListener)vc.csObj;
22 _this.onClick = JSDataExchangeMgr.GetJSArg<UIEventListener.VoidDelegate>(()=>{
23 if (JSApi.isFunctionS((int)JSApi.GetType.Arg))
24 return UIEventListener_onClick_GetDelegate_member2_arg0(JSApi.getFunctionS((int)JSApi.GetType.Arg));
25 else
26 return (UIEventListener.VoidDelegate)vc.datax.getObject((int)JSApi.GetType.Arg);
27 })
28 ;
29 }
30 }

第22行在赋值 onClick 字段。因为 onClick 是 Delegate,所以赋值也要给他一个 Delegate,这个 Delegate 是由函数 UIEventListener_onClick_GetDelegate_member2_arg0 返回的(第1行)。

第24行首先调用 JSApi.getFunctionS(..) 获取 JS 函数 ID。CSRepresentedObject 只是对 JS 对象的一个封装而已。UIEventListener_onClick_GetDelegate_member2_arg0 拿到这个函数ID后,

构造了一个 UIEventListener.VoidDelegate 类型的 Delegate ,最终赋值给了 UIEventListener.onClick。

以上是比较简单的情况:将 JS 函数存储在 C#。

再来看一种情况,将 C# 函数存储在 JS。

// C#

1 TweenEasingCallback func = TweenEasingFunctions.GetFunction(this.EaseType );
2
3 transform.TweenPosition()
4 .SetEndValue( transform.position + ( Vector3.right * 9f ) )
5 .SetDelay( 0.5f, false )
6 .SetDuration( 1.33f )
7 .SetEasing( func )
8 .SetLoopType( TweenLoopType.Loop )
9 .Play();

// JS代码

1 var func = DaikonForge.Tween.TweenEasingFunctions.GetFunction(this.EaseType); // get a delegate from C# (1)
2 TweenTransformExtensions.TweenPosition$$Transform(this.get_transform())
3 .SetEndValue(UnityEngine.Vector3.op_Addition(this.get_transform().get_position(), (UnityEngine.Vector3.op_Multiply$$Vector3$$Single(UnityEngine.Vector3.get_right(), 9))))
4 .SetDelay$$Single$$Boolean(0.5, false)
5 .SetDuration(1.33)
6 .SetEasing(func) // give back to C# (2)
7 .SetLoopType(1)
8 .Play();

这种情况下也是要事先将 TweenEasingFunctions 配置到 JSBindingSettings.classes,让他导出,JS才可以使用。

// TweenEasingFunctions.GetFunction 的绑定代码:

 1 static bool TweenEasingFunctions_GetFunction__EasingType(JSVCall vc, int argc)
2 {
3 int len = argc;
4 if (len == 1)
5 {
6 DaikonForge.Tween.EasingType arg0 = (DaikonForge.Tween.EasingType)JSApi.getEnum((int)JSApi.GetType.Arg);
7 JSMgr.vCall.datax.setObject((int)JSApi.SetType.Rval, DaikonForge.Tween.TweenEasingFunctions.GetFunction(arg0));
8 }
9
10 return true;
11 }

可以看到,当 JS 从 C# 获得一个 delegate 时,会调用 JSDataExchange.setObject 函数。

这里不贴出 setObject 的具体代码,请查看源代码。

在 setObject 函数中,会判断,如果这个对象是个 delegate,那么就创建一个 JSRepresentedObject 对象返回给 JS,同时保存这2者的对应关系。

JSRepresentedObject 的定义在 StreamingAssets/JavaScript/SharpKit/myclrhandler.javascript 最前面。

那么,JS拿到这个对象后,是无法使用的。因为他是C#这边的函数。他只能把这个东西再还给C#。请看上面JS代码标记 (2) 那一句。当他返回给C#时,C#可以根据之前存储的对应关系找到 Delegate。

返回首页:

Unity代码热更新方案 JSBinding + SharpKit 首页

JSBinding + SharpKit / 原理篇:Delegate的更多相关文章

  1. JSBinding + SharpKit / 原理篇:内存管理与垃圾回收

    C# 和 JS 都有垃圾回收机制,需要保证 2 者能够分工协作. 类对象 类在C#中是引用类型.我们在 C# 中维护了2个map,保存 C# 对象和 JS 对象的一一对应关系. 举一个例子,看以下代码 ...

  2. Unity代码热更新方案 JSBinding + SharpKit 首页

    目前Unity的代码更新方案有很多,主要以lua为主. JSBinding + SharpKit 是一种新的技术,他做了两件事情: JSBinding将C#导出到 JavaScript (引擎是 Mo ...

  3. JSBinding+SharpKit / 更新的原理

    首先,其实不是热更新,而是更新. 热更新意思是不重启游戏,但只要你脚本里有存储数据,就不可能.所以只能叫更新. 但大家都这么说,所以... 先举个具体的例子: 如果是C#:在 Prefab 的 Gam ...

  4. JSBinding + SharpKit / Coroutine支持

    首先得深入了解协程的原理.如果还没有完全理解,建议看这篇: http://wiki.unity3d.com/index.php/CoroutineScheduler 另外还要对 JavaScript ...

  5. JSBinding + SharpKit / 需要注意及不支持的列表

    1) 序列化不支持 public List<T>,其余都支持(JSBinding+Bridge无此功能) 2015年11月5日 补充:序列化只处理 Field.目前发现 Animation ...

  6. Cesium原理篇:5最长的一帧之影像

    如果把地球比做一个人,地形就相当于这个人的骨骼,而影像就相当于这个人的外表了.之前的几个系列,我们全面的介绍了Cesium的地形内容,详见: Cesium原理篇:1最长的一帧之渲染调度 Cesium原 ...

  7. Cesium原理篇:3最长的一帧之地形(2:高度图)

           这一篇,接着上一篇,内容集中在高度图方式构建地球网格的细节方面.        此时,Globe对每一个切片(GlobeSurfaceTile)创建对应的TileTerrain类,用来维 ...

  8. Cesium原理篇:7最长的一帧之Entity(下)

    上一篇,我们介绍了当我们添加一个Entity时,通过Graphics封装其对应参数,通过EntityCollection.Add方法,将EntityCollection的Entity传递到DataSo ...

  9. Esfog_UnityShader教程_遮挡描边(原理篇)

    咳咳,有段时间没有更新了,最近有点懒!把不少精力都放在C++身上了.闲言少叙,今天要讲的可和之前的几篇有所不同了,这次是一个次综合应用.这篇内容中与之前不同主要体现在下面几点上. 1.之前我们写的都是 ...

随机推荐

  1. python 绘图工具 matplotlib 入门

    转自: http://www.cnblogs.com/kaituorensheng/p/3440273.html matplotlib 是python最著名的绘图库,它提供了一整套和matlab相似的 ...

  2. 《JAVA笔记 day08 静态_单例》

    //static关键字: /* 静态方法的使用注意事项: 1,静态方法不能访问非静态的成员. 但是非静态是可以访问静态成员的. 说明:静态的弊端在于访问出现了局限性.好处是可以直接别类名调用. 2,静 ...

  3. 2016 - 1 -19 初学HTML5 第一天

    1.HTML COMMANDS MHTL commands called elements.Usually, an element has a start tag and an end tag e.g ...

  4. 多动手试试,其实List类型的变量在页面上取到的值可以直接赋值给一个js的Array数组变量

    多动手试试,其实List类型的变量在页面上取到的值可以直接赋值给一个js的Array数组变量,并且数组变量可以直接取到每一个元素var array1 = '<%=yearList =>'; ...

  5. Git ~ 添加远程仓库 ~Git

    现在的情景是 , 你已经在本地创建了一个Git仓库后 , 又想在 Github 创建一个Git 仓库并且让这两个仓库进行远程同步 , 这样Github 上的仓库既可以作为备份 ,有可以让其他人通过仓库 ...

  6. 封装数据库mysql, mysqli

    <?php header("content-type:text/html;charset=utf-8"); class db{    //私有的静态属性    private ...

  7. IIS发布错误

    发布程序时遇到的错误:

  8. # 20145210 《Java程序设计》第04周学习总结

    教材学习内容总结 第六章 继承 •继承:继承基本上就是避免多个类间重复定义共同行为. 我理解的就是:在编写程序的过程中可能会出现部分代码重复的现象,把重复的部分单独定义为一类(父类),在其他代码中(子 ...

  9. GridView 分页方法

    要实现GrdView分页的功能. 操作如下: 1.更改GrdView控件的AllowPaging属性为true. 2.更改GrdView控件的PageSize属性为 任意数值(默认为10) 3.更改G ...

  10. 在windows下安装GIT

    Git是一个免费的.开源的版本控制软件.在Windows上安装git,一般为msysgit,官方下载地址为:http://code.google.com/p/msysgit/downloads/lis ...