JSBinding + SharpKit / 实战:转换 2DPlatformer

最后修改:2015年07月29日

2016年2月25日

 

2DPlatformer 是 Unity3D 的一个官方 Demo。本文将介绍使用 JSBinging + SharpKit 转换 2DPlatformer 的过程。

本文并不详细介绍每个步骤的细节。因为他们将在其他文章里做详细介绍。

 

准备工作:首先准备好 JSBinding 的工程,正确导入 JSBinding 插件。

2DPlatformer 是Unity3D的第一个示例代码,一共不到10M。麻雀虽小,五脏俱全。牵扯到很多东西,比如 prefab 的使用,结构体序列化,场景切换,音乐等等。

我们的目标是:在已有的工程中,不添加/更新任何C#代码,不用JS重写任何C#代码,花费最少的时间把整个 2DPlatformer 游戏添加进去。

 

分析:

  1. 2DPlatformer 的 C# 代码全部都在 2DPlatformer/Scripts/ 文件夹中。现在需求是不允许更新C#代码,那么我们最终得把这个文件夹删掉
  2. 既然要删掉所有的C#代码,那功能由谁来实现呢?此时强大的 SharpKit 出场了。他可以自动把 C# 代码转换在 JS 代码。

 

下载:

Unity官方原版 2DPlatformer(版本2.1):https://www.assetstore.unity3d.com/en/#!/content/11228

 

以下是具体步骤:

 

1. 将 2DPlatformer 导入到工程中,并确定C#版本能够正确运行

为了方便,导入后,建立一个 2DPlatformer 文件夹,把东西都拖进去。如图。

放完后一定要确保能够正常运行,因为项目包含 Project Settings ,如果没有正确导入,C#版本本身就会出错。

 

2. 配置 JSBindingSettings.classes

这里给出的是 2D Platformer 所有用到的类型,可以将这个数组替换掉代码中的 JSBindingSettings.classes 数组。

应该是不改也可以,因为代码里 JSBindingSettings.classes 数组已经包含下面这些类了。

public static Type[] classes = new Type[]
    {
        typeof(PerTest),
        typeof(PerTest.RefObject),

        typeof(Debug),
        typeof(Input),
        typeof(GameObject),
        typeof(Transform),
        typeof(Vector2),
        typeof(Vector3),
        typeof(MonoBehaviour),
        typeof(Behaviour),
        typeof(Component),
        typeof(UnityEngine.Object),
        typeof(YieldInstruction),
        typeof(WaitForSeconds),
        typeof(WWW),
        typeof(Application),
        typeof(UnityEngine.Time),
        typeof(Resources),
        typeof(TextAsset),
        
        typeof(IEnumerator),
        typeof(List<>),
        typeof(List<>.Enumerator),
        typeof(Dictionary<,>),
        typeof(Dictionary<,>.KeyCollection), 
        typeof(Dictionary<,>.ValueCollection), 
        typeof(Dictionary<,>.Enumerator), 
        typeof(KeyValuePair<,>), 
        
        typeof(System.Diagnostics.Stopwatch),
        typeof(UnityEngine.Random),
        typeof(StringBuilder),

        typeof(System.Xml.XmlNode),
        typeof(System.Xml.XmlDocument),
        typeof(System.Xml.XmlNodeList),
        typeof(System.Xml.XmlElement),
        typeof(System.Xml.XmlLinkedNode),
        typeof(System.Xml.XmlAttributeCollection),
        typeof(System.Xml.XmlNamedNodeMap),
        typeof(System.Xml.XmlAttribute),

        // for 2d platformer
        typeof(LayerMask),
        typeof(Physics2D),
        typeof(Rigidbody2D),
        typeof(Collision2D),
        typeof(RaycastHit2D),
        typeof(AudioClip),
        typeof(AudioSource),
        typeof(ParticleSystem),
        typeof(Renderer),
        typeof(ParticleSystemRenderer),
        typeof(DateTime),
        typeof(GUIElement),
        typeof(GUIText),
        typeof(GUITexture),
        typeof(SpriteRenderer),
        typeof(Animator),
        typeof(Camera),
        typeof(Mathf),
        typeof(Quaternion),
        typeof(Sprite),
        typeof(Collider2D),
        typeof(BoxCollider2D),
        typeof(CircleCollider2D),
        typeof(Material),
        typeof(Color),
        typeof(PolygonCollider2D),
    };

 

3. 生成JS绑定

配置好 JSBindingSettings.classes 后就可以生成绑定了。

点击菜单:【JSB | Generate JS and CS Bindings

(如果 Unity 版本没改,JSBindingSettings.classes 的列表也没有变化,此步骤如已执行过不需要再执行)

 

4. 正确配置 JSBindingSettings 里的各个导出路径设置

需要配置以下几个参数,路径都是相对于 Assets 文件夹

PathsNotToJavaScript:简称为A,是指哪些路径不要转换成JS。比如说类库,或者 JSBinding 本身。

PathsToJavaScript:简称为B,是指那些在A中路径下的,但是又要导出的。

 

有点乱,详细解释一下。A和B是用于配置哪些路径要保留C#,哪些路径下的C#要转换成JS。

通常来说,基础框架代码是不需要转换成JS的,而且是相对固定的,比较少会进行改动。所以把这些路径配置到A数组。

这样就表示,除了A以外的其他路径里的C#类,都将被标记 [JsType(...)]标签,之后将被 SharpKit 编译生成JS代码。

而B是啥呢?B只是用于对A做一些例外,就是属于A数组,但是又要被转换成JS的。比如说,JSBinding/ 因为是插件源代码,肯定不转换成JS,所以 JSBinding/ 会配置在A数组里。

但是我们在 JSBinding/Samples 里放了一些示例代码,我希望他们被编译成JS,所以我就把 JSBinding/Samples 配置在B里,表示要转换。

 

PathsNotToCheckOrReplace:简称C。

跟A和B类似,但是用于说明 prefab 的处理。对于脚本,我们是将其编译成JS,才可以进行更新。对于 prefab,因为 prefab 上绑定了脚本,那么必须要解除这个绑定关系才可以。

解除的方法是将脚本都替换成 JSComponent,这里不详细解释。C这个数组用于说明,不要对哪些路径下的 prefab 进行处理。比如说 "JSBinding/Prefabs/_JSEngine.prefab" 是不需要处理的。

NGUI/ 路径下的 prefab 也不需要处理,因为这些 prefab 不会绑定要被导成JS的C#脚本。

 1     /*
 2      * Formula:
 3      * All C# scripts - PathsNotToJavaScript + PathsToJavaScript = C# scripts to export to javascript
 4      * see JSAnalyzer.MakeJsTypeAttributeInSrc for more information
 5      */
 6     public static string[] PathsNotToJavaScript = new string[]
 7     {
 8         "JSBinding/",
 9         "Stealth/",
10         "DaikonForge Tween (Pro)/",
11         "NGUI/",
12     };
13     public static string[] PathsToJavaScript = new string[]
14     {
15         "JSBinding/Samples/",
16         "DaikonForge Tween (Pro)/Examples/Scripts",
17     };
18     /// <summary>
19     /// By default, menu
20     /// 
21     /// JSB | Check All Monos for all Prefabs and Scenes
22     /// JSB | Replace All Monos for all Prefabs and Scenes
23     /// 
24     /// handles all Prefabs and Scenes in whole project
25     /// add paths(directory or file name) to this array if you want to skip them
26     /// </summary>
27     public static string[] PathsNotToCheckOrReplace = new string[]
28     {
29         "JSBinding/",
30         "JSBinding/Prefabs/_JSEngine.prefab",
31         "Plugins/",
32         "Resources/",
33         "Src/",
34         "StreamingAssets/",
35         "UnityVS/",
36         "DaikonForge Tween (Pro)/",
37         "NGUI/",
38     };
View Code

 

 

5. 往2DPlatformer 的所有 C# 源代码中的类和结构体添加 [JsType()] 标记。

上一个步骤已经配置好了,这一步只要运行菜单即可。

运行菜单:【JSB | Add JsType Attribute for all structs and classes

 

修改后会有像下面这样的变化:

// 原来的代码

1 using UnityEngine;
2 using System.Collections;
3 
4 public class Gun : MonoBehaviour
5 {
6     public GameObject rocketGO;                // Prefab of the rocket.
7     public float speed = 20f;                // The speed the rocket will fire at.

// 执行菜单后(生成了 [JsType()] 标记):

1 using UnityEngine;
2 using System.Collections;
3 
4 using SharpKit.JavaScript;
5 [JsType(JsMode.Clr,"../../StreamingAssets/JavaScript/SharpKitGenerated/2DPlatformer/Scripts/Gun.javascript")]
6 public class Gun : MonoBehaviour
7 {
8     public GameObject rocketGO;                // Prefab of the rocket.
9     public float speed = 20f;                // The speed the rocket will fire at.

 

6. 对代码进行少量修改

6.1 往以下几个文件添加这段代码:

(为啥:请看 JSBinding + SharpKit / Coroutine支持

// 文件

  1. BackgroundPropSpawner.cs
  2. Bomb.cs
  3. PickupSpawner.cs
  4. Remover.cs
  5. Spawner.cs

// 要添加的代码

void LateUpdate()
{
    jsimp.Coroutine.UpdateCoroutineAndInvoke(this);
}

 

6.2 对 BackgroundPropSpawner.cs 文件做如下修改(明确从 while 中 break 出来,而不是判断 object 是不是变成空了):

(为啥:对GameObject go调用 Destroy后,在C#中 (go == null) 为 true,但 JavaScript 为 false。)

// 修改前:

 1                 // While the prop exists...
 2         while(propInstance != null)
 3         {
 4             // ... and if it's facing left...
 5             if(facingLeft)
 6             {
 7                 // ... and if it's beyond the left spawn position...
 8                 if(propInstance.transform.position.x < leftSpawnPosX - 0.5f)
 9                     // ... destroy the prop.
10                     Destroy(propInstance.gameObject);
11             }
12             else
13             {
14                 // Otherwise, if the prop is facing right and it's beyond the right spawn position...
15                 if(propInstance.transform.position.x > rightSpawnPosX + 0.5f)
16                     // ... destroy the prop.
17                     Destroy(propInstance.gameObject);
18             }
19 
20             // Return to this point after the next update.
21             yield return null;
22         }

// 修改后:

 1         while(propInstance != null)
 2         {
 3             // ... and if it's facing left...
 4             if(facingLeft)
 5             {
 6                 // ... and if it's beyond the left spawn position...
 7                 if(propInstance.transform.position.x < leftSpawnPosX - 0.5f)
 8                 {
 9                     // ... destroy the prop.
10                     Destroy(propInstance.gameObject);
11                     break;
12                 }
13             }
14             else
15             {
16                 // Otherwise, if the prop is facing right and it's beyond the right spawn position...
17                 if(propInstance.transform.position.x > rightSpawnPosX + 0.5f)
18                 {
19                     // ... destroy the prop.
20                     Destroy(propInstance.gameObject);
21                     break;
22                 }
23             }
24 
25             // Return to this point after the next update.
26             yield return null;
27         }

 

6.3 往 JSComponent 添加以下代码到合适的位置(打开代码你就知道该怎么加了,也可能已经有了,只是注释掉了,取消注释即可)

(为啥需要这一步?2DPlatformer 从动画 SendMessage 去执行 MonoBehaviour 代码,我们不支持、也不推荐这种方式,但他既然用了,我们先暂时特殊支持一下)

// 1 添加这3个变量定义到类中
    int idDestroyChildGameObject = 0;
    int idDisableChildGameObject = 0;
    int idDestroyGameObject = 0;

// 2 添加这3个成员初始化到函数 initMemberFunction 中
    idDestroyChildGameObject = JSApi.getObjFunction(jsObjID, "DestroyChildGameObject");
    idDisableChildGameObject = JSApi.getObjFunction(jsObjID, "DisableChildGameObject");
    idDestroyGameObject = JSApi.getObjFunction(jsObjID, "DestroyGameObject");

// 3 添加这3个函数到类中
    void DestroyChildGameObject()
    {
        callIfExist(idDestroyChildGameObject);
    }

    void DisableChildGameObject()
    {
        callIfExist(idDisableChildGameObject);
    }

    void DestroyGameObject()
    {
        callIfExist(idDestroyGameObject);
    }

 

7. 生成一个 js 文件,记录每个脚本要对应哪个JSComponent。

执行菜单:【JSB | Generate MonoBehaviour to JSComponent_XX

这一步是提前计算每个 MonoBehaviour 脚本,要使用哪个 JSComponent 文件进行对应。

生成了文件:StreamingAssets/JavaScript/MonoBehaviour2JSComponentName.javascript,打开这个文件看看就会明白了。

 

8. 【JSB | Compile Cs to Js】

编译完成后  将在 StreamingAssets/JavaScript/SharpKitGeneratedFiles.javascript 文件里找到 2DPlatformer 的所有代码。

 

9. 解除所有 prefab 及 场景中GameObject 对 C# 源代码的引用

因为我们最终的目的是要删除整个 2DPlatformer/Scripts 文件夹,那么任何 prefab 及 GameObject 显然都不可以引用任何 C# 源代码。

对于 MonoBehaviour 来说,我们的做法是将其替换成固定的类 JSComponent,这个类足够强大,可以支持绝大部分继承于 MonoBehaviour 的类,最主要的是支持序列化。

对于其他类或结构体,他们都将被转换为 JS 代码,GameObject 不会引用到。

在真正的项目中使用时,最好先备份,再执行这个菜单。

执行菜单:[JSB | Replace all monos for all Prefabs and Scenes]

 

Replace.txt 示例。显示了所有将要被处理的 prefab 及 scene。刚好包含了所有 2DPlatformer 的所有东西。确定好了就点OK吧!让奇迹发生~

 1 2DPlatformer/Prefabs/Characters/enemy1.prefab
 2 2DPlatformer/Prefabs/Characters/enemy2.prefab
 3 2DPlatformer/Prefabs/Characters/hero.prefab
 4 2DPlatformer/Prefabs/Environment/backgroundAnimation.prefab
 5 2DPlatformer/Prefabs/Environment/backgrounds.prefab
 6 2DPlatformer/Prefabs/Environment/Bus.prefab
 7 2DPlatformer/Prefabs/Environment/Cab.prefab
 8 2DPlatformer/Prefabs/Environment/env_clouds.prefab
 9 2DPlatformer/Prefabs/Environment/env_fog.prefab
10 2DPlatformer/Prefabs/Environment/env_riverMid.prefab
11 2DPlatformer/Prefabs/Environment/env_riverTop.prefab
12 2DPlatformer/Prefabs/Environment/Foregrounds.prefab
13 2DPlatformer/Prefabs/FX/part_splash.prefab
14 2DPlatformer/Prefabs/FX/part_warp.prefab
15 2DPlatformer/Prefabs/FX/splash.prefab
16 2DPlatformer/Prefabs/killTrigger.prefab
17 2DPlatformer/Prefabs/mainCamera.prefab
18 2DPlatformer/Prefabs/pickupManager.prefab
19 2DPlatformer/Prefabs/platformEnd.prefab
20 2DPlatformer/Prefabs/Props/bomb.prefab
21 2DPlatformer/Prefabs/Props/bombCrate.prefab
22 2DPlatformer/Prefabs/Props/explosionCircle.prefab
23 2DPlatformer/Prefabs/Props/explosionParticle.prefab
24 2DPlatformer/Prefabs/Props/healthCrate.prefab
25 2DPlatformer/Prefabs/Props/rocket.prefab
26 2DPlatformer/Prefabs/Props/rocketExplosion.prefab
27 2DPlatformer/Prefabs/Props/swan.prefab
28 2DPlatformer/Prefabs/spawner.prefab
29 2DPlatformer/Prefabs/UI/ui_100points.prefab
30 2DPlatformer/Prefabs/UI/ui_bombHUD.prefab
31 2DPlatformer/Prefabs/UI/ui_healthDisplay.prefab
32 2DPlatformer/Scenes/Level.unity

 

菜单执行前:

执行菜单后:

 

添加一个 JSEngine.prefab 到场景中

场景是:2DPlatformer/Scenes/Level.unity

 

运行!

 

运行成功后,删除 2DPlatformer/Scripts/ 文件夹

 

Windows版本可执行程序截图:

 

 

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

posted on 2015-05-04 21:24  AnswerWinner  阅读(1815)  评论(0编辑  收藏  举报

导航