JSBinding + SharpKit / 原理篇:Delegate
以 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的更多相关文章
- JSBinding + SharpKit / 原理篇:内存管理与垃圾回收
C# 和 JS 都有垃圾回收机制,需要保证 2 者能够分工协作. 类对象 类在C#中是引用类型.我们在 C# 中维护了2个map,保存 C# 对象和 JS 对象的一一对应关系. 举一个例子,看以下代码 ...
- Unity代码热更新方案 JSBinding + SharpKit 首页
目前Unity的代码更新方案有很多,主要以lua为主. JSBinding + SharpKit 是一种新的技术,他做了两件事情: JSBinding将C#导出到 JavaScript (引擎是 Mo ...
- JSBinding+SharpKit / 更新的原理
首先,其实不是热更新,而是更新. 热更新意思是不重启游戏,但只要你脚本里有存储数据,就不可能.所以只能叫更新. 但大家都这么说,所以... 先举个具体的例子: 如果是C#:在 Prefab 的 Gam ...
- JSBinding + SharpKit / Coroutine支持
首先得深入了解协程的原理.如果还没有完全理解,建议看这篇: http://wiki.unity3d.com/index.php/CoroutineScheduler 另外还要对 JavaScript ...
- JSBinding + SharpKit / 需要注意及不支持的列表
1) 序列化不支持 public List<T>,其余都支持(JSBinding+Bridge无此功能) 2015年11月5日 补充:序列化只处理 Field.目前发现 Animation ...
- Cesium原理篇:5最长的一帧之影像
如果把地球比做一个人,地形就相当于这个人的骨骼,而影像就相当于这个人的外表了.之前的几个系列,我们全面的介绍了Cesium的地形内容,详见: Cesium原理篇:1最长的一帧之渲染调度 Cesium原 ...
- Cesium原理篇:3最长的一帧之地形(2:高度图)
这一篇,接着上一篇,内容集中在高度图方式构建地球网格的细节方面. 此时,Globe对每一个切片(GlobeSurfaceTile)创建对应的TileTerrain类,用来维 ...
- Cesium原理篇:7最长的一帧之Entity(下)
上一篇,我们介绍了当我们添加一个Entity时,通过Graphics封装其对应参数,通过EntityCollection.Add方法,将EntityCollection的Entity传递到DataSo ...
- Esfog_UnityShader教程_遮挡描边(原理篇)
咳咳,有段时间没有更新了,最近有点懒!把不少精力都放在C++身上了.闲言少叙,今天要讲的可和之前的几篇有所不同了,这次是一个次综合应用.这篇内容中与之前不同主要体现在下面几点上. 1.之前我们写的都是 ...
随机推荐
- SQL Server LEFT Functions
LEFT(string, n)函数,是处理字符数据获取子字符串.第一个参数是将要处理的字符串,第二个参数,是从字符串的左边开始截取的字符个数. 例子: DECLARE @string NVARCHAR ...
- iOS 在UILabel显示不同的字体和颜色
转自:http://my.oschina.net/CarlHuang/blog/138363 在项目开发中,我们经常会遇到在这样一种情形:在一个UILabel 使用不同的颜色或不同的字体来体现字符串, ...
- 渐进记法(O,Ω,Θ)
第一次在<算法导论>中看到这三种渐进记法的符号,当时对此一窍不通,所以也就没有注意它们,直接把他们忽略了,知道学习算法的时候,才知道当初的做法有多傻,因为一个算法的好坏以及复杂度,可以用它 ...
- linux命令:cd
1.介绍: cd可以说是linux下最基本的命令,全称是change directory. 2.命令格式: cd [DIRECTORY] 3.命令功能: 切换到指定目录 4.常用范例: 例一:切换到根 ...
- 自动打补丁Bat指令
自动打补丁 补丁放于hotfix文件夹下 for %%i in (hotfix\*.exe) do start /wait %%i /z /u
- spring 常见错误
1. 数据库字段和实体字段不匹配,尤其是数据表字段和实体字段的类型不匹配 2. 数据表中日期字段不能为空(sql语句用了聚合函数min或者max),此时数据表中没有数据就会报此类错误.
- GridView 分页方法
要实现GrdView分页的功能. 操作如下: 1.更改GrdView控件的AllowPaging属性为true. 2.更改GrdView控件的PageSize属性为 任意数值(默认为10) 3.更改G ...
- 使用WebMatrix发布网站到Windows Azure
1. 在本地机安装 WebMatrix, 安装Windows Azure SDK 2. 登录Windows Azure, 网站 > 创建一个新网站或选择已有网站 3. 在发布应用程序,选择下载发 ...
- 暴力枚举——Help Me with the Game
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3394 Accepted: 2172 Description You ...
- break return
用 break 跳出循环 用 return 跳出函数 用 continue 结束本次循环开始下次循环