Unity 3D\2D手机游戏开发:从学习到产品(第3版)
上QQ阅读APP看书,第一时间看更新

2.14 自动创建Prefab

经过前面的步骤,我们会发现Unity提供了可视化工具,在编辑器中甚至不用编写代码便可以自由装配Prefab,快速实现游戏中需要的某些功能。但这种方式也有缺点,当一个Prefab比较复杂时,重新装配或修改Prefab需要较多的工作,比如我们要再创建10个不同的敌人,就需要手动重复前面的步骤10次,工作量很大,也容易出错。

所有在Unity编辑器中的手动操作都可以使用代码完成。这样,只需要编写一次代码,很多重复的工作就省掉了。以Enemy2b的Prefab制作为例,我们将完全使用代码来创建它。

步骤 01 首先,我们要编写一个编辑器脚本,它的作用是在当模型被导入到Unity工程中时自动将这个模型创建为Prefab。在工程目录中创建一个名为Editor的文件夹,在里面创建脚本ProcessModel.cs,保存在Editor中的脚本不能在游戏运行时使用。

步骤 02 编辑脚本ProcessModel.cs,添加using UnityEditor,这样就能使用Unity的编辑器相关API。这里定义的ProcessModel类继承自AssetPostprocessor,它专门用来处理资源导入。OnPostprocessModel方法在导入模型时会被自动调用,其中的参数GameObject即是导入的模型。我们在ProcessModel方法中将Enemy2b.fbx直接制作为一个Prefab,并命名为Enemy2c.Prefab,代码如下:

        using UnityEngine;
        using UnityEditor;

        class ProcessModel : AssetPostprocessor
        {
            void OnPostprocessModel( GameObject input )
            {
              // 只处理名为"Enemy2b"的模型
              if (! input.name.Contains("Enemy2b"))
                return;
            // 设置导入模型的tag
            input.tag = "Enemy";

            // 查找碰撞模型
            foreach (Transform obj in input.GetComponentsInChildren<Transform>())
            {
                if (obj.name.CompareTo("col") == 0)
                {
                    // 取消碰撞模型的显示
                    MeshRenderer r = obj.GetComponent<MeshRenderer>();
                    r.enabled = false;

                    // 添加Mesh碰撞体
                    obj.gameObject.AddComponent<MeshCollider>();

                    // 设置碰撞体的tag
                    obj.tag = "Enemy";
                }
                else
                {
                    obj.gameObject.AddComponent<EnemyRenderer>(); //指定Renderer脚本
                }
            }

            // 设置刚体
            Rigidbody rigid = input.AddComponent<Rigidbody>();
            rigid.useGravity = false;
            rigid.isKinematic = true;

            // 取得导入模型的相关信息
            ModelImporter importer = assetImporter as ModelImporter;

            // 从工程中将该模型读出来
      GameObject tar =(GameObject)AssetDatabase.LoadAssetAtPath(importer.assetPath, typeof(GameObject));

            // 将这个模型创建为prefab
      GameObject prefab = (GameObject)PrefabUtility.CreatePrefab("Assets/Prefabs/Enemy2c.prefab", tar );

            // 为prefab添加声音组件
            prefab.AddComponent<AudioSource>();
            // 获得子弹的prefab
                  GameObject rocket =
            (GameObject)AssetDatabase.LoadAssetAtPath("Assets/Prefabs/EnemyRocket.prefab", typeof(GameObject));

                  // 获得爆炸效果的prefab
            var fx =(GameObject)AssetDatabase.LoadAssetAtPath("Assets/FX/Explosion.prefab", typeof(GameObject));

                  // 为prefab添加脚本
                  SuperEnemy enemy=prefab.AddComponent<SuperEnemy>();
                  // 设置脚本的默认参数
                  enemy.m_life = 50;
                  enemy.m_point = 50;
                  enemy.m_rocket= rocket.transform;
                  enemy.m_explosionFX = fx.transform;
              }
            }

重新导入Enemy2b.fbx, ProcessModel.cs会被调用,并自动创建Enemy2c.Prefab,它的所有功能和设置均与前面手动设置的Prefab相同。