以 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. 有关WAMPSERVER 环境搭建 如何修改端口,MySQL数据库的修改

    环境搭建 http://share.weiyun.com/88896747fedd4e8b19afebea18f7684c 一.修改Apache的监听端口 1.在界面中选Apache,弹出隐藏菜单选项 ...

  2. Windows下adb push 总是提示Failed to copy "XX.apk" to 'system/app':Read-only file system

    一般情况看到这种提示我们会想到需要root权限,然后敲上adb remount,但是当我们执行过adb remount后,提示成功,但执行push命令依旧无法完成push. 那么此时我们的做法应该是重 ...

  3. DB Create and Insert

    <?php $servername = "localhost"; $username = "username"; $password = "pa ...

  4. Bootstrap全局css

    HTML中的所有标题标签,<h1>到<h6>均可使用.另外,还提供了.h1到.h6类,为的是给内联(inline)属性的文本赋予标题的样式.在标题内还可以包含<small ...

  5. aspx页面图片用作html中img的url

    背景:如果无法直接访问保存图片的服务器,我们可以先制作一个aspx页面用来接受服务器发送过来的图片,然后html页面请求aspx页面.对图片服务器起一定的缓冲保护作用,预防对黑客攻击造成危害. 注意: ...

  6. 【转】Entity Systems

    “Favour composition over inheritance” If you haven’t already read my previous post on the problems o ...

  7. 设备、像素和点 、 9切片技术 、 颜色和外观 、 NavigationBar的美化

    1 TMessage项目的输入面板界面 1.1 问题 IOS中经常会使用到九切片技术对图片进行处理.本案例使用九切片技术完成Tmessage项目的输入板界面,如图-1所示: 图-1 1.2 方案 首先 ...

  8. HTML-day-2-HTML常用标签

    一.常用标签 超链接标签 href-----hyperlink reference _blank,是指在新窗口中打开. 作用:①做锚点的标签,<a name=””></a> ② ...

  9. 修改Myecclipse servlet/jsp的默认模板

    点击图片下载模板: 用winrar等打开myeclipse安装目录下的com.genuitec.eclipse.wizards*.jar,替换响应文件. 详细版:http://www.cnblogs. ...

  10. archlinux安装图形界面

    安装xorg 检查显卡驱动 $ lspci | grep VGA install X server wiki Then use the $ startx to start the X server, ...