以 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. 理解Mac和iOS中的 Event 处理

    根据现在的理解,我把event处理分为5部分,第一是,Event处理的Architecture:第二是,Event的Dispatch到first responder之前: 第三是,Event从firs ...

  2. Codeforces Round #249 (Div. 2)

    A.水题. #include <cstdio> #include <iostream> #include <cstdlib> #include <cstrin ...

  3. (转)js函数参数设置默认值

    原文:http://www.cnblogs.com/RightDear/archive/2013/06/26/3156652.html js函数参数设置默认值   php有个很方便的用法是在定义函数时 ...

  4. php大力力 [007节]php静态表量

    2015-08-23 php大力力007. php静态表量 这里看一下高老师的视频讲解: 转帖: php中static静态类与static 静态变量用法区别 php中的静态变量的基本用法 转载 时间: ...

  5. HDU 5862(离散化+树状数组)

    Problem Counting Intersections 题目大意 给定n条水平或竖直的线段,统计所有线段的交点个数. (n<=100000) 解题分析 首先将线段离散化. 然后将所有线段按 ...

  6. nno_setup制作升级包必须面临的几个问题 2

    这两天的时间一直在制作应用程序的升级包,期间碰到一些问题这里一并记录下来,相信这是制作升级包必须面临和解决的问题: 1. 升级包安装程序如何不再产生新的安装.卸载程序 Inno_setup中AppId ...

  7. 4 Values whose Sum is 0

      Time Limit:15000MS     Memory Limit:228000KB     64bit IO Format:%I64d & %I64u Submit Status D ...

  8. Debian 入门安装与配置1

    Debian 入门安装与配置1 最近安装了多个发行版本的Linux,包括Ubuntu.Fedora.Centos和Debian,发现只有Debian在界面和稳定性等综合特性上表现最优,自己也最喜欢,所 ...

  9. CentOS x64安装Virtualbox

    今天在CentOS 6.5 x64系统上装了个Virtualbox,这里记录下整个安装过程. 1.去官网下载Virtualbox及其扩展包,同时还要下载dkms,具体如下: Virtualbox:ht ...

  10. Activity Lifecycle

    Activity Lifecycle Activities in the system are managed as an activity stack(activity栈?). When a new ...