本文大部分转载,作者做了关于配置文件生成工作,但是很遗憾,关于position和rotation信息目前尚未自动生成,运行本例的朋友,需要自己手动添加位置和角度信息,否则程序会报错。
标准的json数据:

    1. {
    2.     "AssetList" : [{
    3.         "Name" : "Chair 1",
    4.         "Source" : "Prefabs/Chair001.unity3d",
    5.         "Position" : [2,0,-5],
    6.         "Rotation" : [0.0,60.0,0.0]
    7.     },
    8.     {
    9.         "Name" : "Chair 2",
    10.         "Source" : "Prefabs/Chair001.unity3d",
    11.         "Position" : [1,0,-5],
    12.         "Rotation" : [0.0,0.0,0.0]
    13.     },
    14.     {
    15.         "Name" : "Vanity",
    16.         "Source" : "Prefabs/vanity001.unity3d",
    17.         "Position" : [0,0,-4],
    18.         "Rotation" : [0.0,0.0,0.0]
    19.     }
    20.     }]
    21. }

    用Unity3D制作基于web的网络游戏,不可避免的会用到一个技术-资源动态加载。比如想加载一个大场景的资源,不应该在游戏的开始让用户长时间等待全部资源的加载完毕。应该优先加载用户附近的场景资源,在游戏的过程中,不影响操作的情况下,后台加载剩余的资源,直到所有加载完毕。


    在讲述代码之前,先想象这样一个网络游戏的开发流程。首先美工制作场景资源的3D建模,游戏设计人员把3D建模导进Unity3D,托托拽拽编辑场景,完成后把每个gameobject导出成XXX.unity3d格式的资源文件(参看BuildPipeline),并且把整个场景的信息生成一个配置文件,xml或者Json格式(本文使用Json)。最后还要把资源文件和场景配置文件上传到服务器,最好使用CMS管理。客户端运行游戏时,先读取服务器的场景配置文件,再根据玩家的位置从服务器下载相应的资源文件并加载,然后开始游戏,注意这里并不是下载所有的场景资源。在游戏的过程中,后台继续加载资源直到所有加载完毕。

    json.txt:(注:当生成的json无法读取时,记得改一下编码格式 改成 ANSI)

    {"AssetList":[{"Name":"Sphere","Source":"Prefabs/Sphere.unity3d"},{"Name":"cube","Source":"Prefabs/cube.unity3d"},{"Name":"Sphere","Source":"Prefabs/Sphere.unity3d"},{"Name":"cube","Source":"Prefabs/cube.unity3d"}]}


    主程序:

    1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class MainMonoBehavior : MonoBehaviour {
     5 
     6     public delegate void MainEventHandler(GameObject dispatcher);
     7     public event MainEventHandler StartEvent;
     8     public event MainEventHandler UpdateEvent;
     9     public void Start()
    10     {
    11         ResourceManager.getInstance().LoadSence("Scenes/json.txt");//json配置文件
    12         if(StartEvent != null)
    13         {
    14             StartEvent(this.gameObject);
    15         }
    16     }
    17     public void Update()
    18     {
    19         if (UpdateEvent != null)
    20         {
    21             UpdateEvent(this.gameObject);
    22         }
    23     }
    24 }

     

    这里面用到了C#的事件机制,大家可以看看我以前翻译过的国外一个牛人的文章。C# 事件和Unity3D在 start方法里调用ResourceManager,先加载配置文件。每一次调用update方法,MainMonoBehavior会把update 事件分发给ResourceManager,因为ResourceManager注册了MainMonoBehavior的update事件。


    辅助类:

    unity加载fbx动画 unity动态加载fbx文件_Source

    unity加载fbx动画 unity动态加载fbx文件_json_02

    ResourceManager.cs


    1 using UnityEngine;
      2 using System.Collections;
      3 using System.Collections.Generic;
      4 using LitJson;
      5 using System.Net;
      6 public class ResourceManager
      7 {
      8 
      9 // Use this for initialization
     10         private MainMonoBehavior mainMonoBehavior;
     11         private   string mResourcePath;
     12         private Scene mScene;
     13         private Asset mSceneAsset;
     14         private static ResourceManager resourceManager=new ResourceManager();//如果没有new 会出现没有实例化的错误
     15         private Dictionary<string ,WWW > wwwCacheMap=new Dictionary<string,WWW>();//这个新添加的原文代码中没有定义它 应该是个字典
     16        public static  ResourceManager getInstance( )
     17         {
     18                 return resourceManager;//静态函数中不能使用非静态成员
     19         }
     20         public  ResourceManager()
     21         {
     22                 mainMonoBehavior = GameObject.Find("Main Camera").GetComponent<MainMonoBehavior>();
     23                 mResourcePath ="file://"+Application.dataPath+"/..";
     24         }
     25        
     26         public void LoadSence(string fileName)
     27         {
     28                 //Debug.Log(fileName);
     29                 mSceneAsset = new Asset();
     30                 mSceneAsset.Type = Asset.TYPE_JSON;//后面类型判断有用
     31                 mSceneAsset.Source = fileName;
     32                 mainMonoBehavior.UpdateEvent += OnUpdate;//添加监听函数
     33         }
     34 
     35 
     36 
     37         public void OnUpdate(GameObject dispatcher)//该函数是监听函数,每帧都会被调用(它的添加是在MainMonoBehavior的start函数中通过调用本地LoadSence函数)
     38         {
     39                 if (mSceneAsset != null)//表示已经通过了new操作分配类内存空间但是资源还没有加载完
     40                 {
     41                         LoadAsset(mSceneAsset);//这个函数里面会通过判断,使www的new操作只执行一次
     42                         if (!mSceneAsset.isLoadFinished)//C#中 bool类型默认是false
     43                         {
     44                                return;
     45                         }
     46                         mScene = null;
     47                         mSceneAsset = null;
     48                 }
     49                 mainMonoBehavior.UpdateEvent -= OnUpdate;//当所有资源被加载后,删除监听函数。
     50         }
     51         //最核心的函数
     52      private Asset LoadAsset(Asset asset)
     53         {
     54                 string fullFileName =mResourcePath+"/"+ asset.Source;// mResourcePath + "/" + asset.Source;
     55                 Debug.Log("fullFileName=" + fullFileName);
     56                 //if www resource is new, set into www cache
     57                 if (!wwwCacheMap.ContainsKey(fullFileName))
     58                 {//自定义字典 查看开头的定义
     59                         if (asset.www == null)
     60                         {//表示www还没有new操作
     61                                 asset.www = new WWW(fullFileName);
     62                                 return null;
     63                         }
     64                         if (!asset.www.isDone)
     65                         {
     66                                 return null;
     67                         }
     68                         wwwCacheMap.Add(fullFileName, asset.www); //该字典是作为缓存的作用,如果之前已经加载过同样的Unity3D格式文件,那么不需要在加载,直接拿来用就行了。  
     69                 }  
     70                 if (asset.Type == Asset.TYPE_JSON)
     71                 { //Json 表示当txt文件被首次加载时的处理
     72                         if (mScene == null)
     73                         {        
     74                             string jsonTxt = mSceneAsset.www.text;
     75                             Debug.Log("jsonTxt=" + jsonTxt);
     76                             mScene = JsonMapper.ToObject<Scene>(jsonTxt);//mScene是个Asset对象列表,也就是Json文件需要一个AssetList列表对象,注意名字的统一,列表中Asset对象中的成员名称要和txt                //文件中的相关名称统一 不然JsonMapper无法找到
     77                          }
     78                         //load scene
     79                         foreach (Asset sceneAsset in mScene.AssetList)
     80                         {
     81                                 if (sceneAsset.isLoadFinished)
     82                                 {
     83                                         continue;
     84                                 }
     85                                 else
     86                                 {
     87                                         LoadAsset(sceneAsset);//这里的处理就是 下面 Asset.TYPE_GAMEOBJECT的处理方式,注意是递归函数的调用
     88                                         if (!sceneAsset.isLoadFinished)
     89                                         {
     90                                             return null;
     91                                          }
     92                                  }
     93                         }
     94                 }
     95                 else if (asset.Type == Asset.TYPE_GAMEOBJECT)//处理文件中具体信息,嵌套关系或者直接是一个GameObject对象,与上面的代码有联系,Asset创建时候的构造函数中设置成
     96                 //TYPE_GAMEOBJECT类型
     97                 { //Gameobject
     98                         if (asset.gameObject == null)//如果不为null 表示已经通过wwwCacheMap加载了资源包中所包含的资源(fullFileName仅仅是一个文件,资源包中资源是分散的GameObject对象),不需要在重新加载
     99                         {
    100                                 wwwCacheMap[fullFileName].assetBundle.LoadAll();//已经通过new WWW操作完成了加载,该函数用来加载包含着资源包中的资源
    101                                 GameObject go = (GameObject)GameObject.Instantiate(wwwCacheMap[fullFileName].assetBundle.mainAsset);
    102                                 UpdateGameObject(go, asset);
    103                                 asset.gameObject = go;
    104                         }
    105                         if (asset.AssetList != null)//有嵌套关系
    106                         {
    107                                 foreach (Asset assetChild in asset.AssetList)
    108                                 {
    109                                         if (assetChild.isLoadFinished)
    110                                         {
    111                                                 continue;
    112                                         }
    113                                         else
    114                                         {
    115                                                 Asset assetRet = LoadAsset(assetChild);
    116                                                 if (assetRet != null)//这个if else 语句是为了防止你的配置文件中的GameObject对象路径不正确,导致访问空指针。
    117                                                 {
    118                                                         assetRet.gameObject.transform.parent = asset.gameObject.transform;
    119                                                 }
    120                                                 else
    121                                                 {
    122                                                         return null;
    123                                                 }
    124                                         }
    125                                 }
    126                         }
    127                 }
    128                 asset.isLoadFinished = true;
    129                 return asset;
    130         }
    131         private void UpdateGameObject(GameObject go, Asset asset)
    132         {
    133                 //name
    134                 go.name = asset.Name;
    135                 //position
    136                 Vector3 vector3 = new Vector3((float)asset.Position[0], (float)asset.Position[1], (float)asset.Position[2]);
    137                 go.transform.position = vector3;
    138                 //rotation
    139                vector3 = new Vector3((float)asset.Rotation[0], (float)asset.Rotation[1], (float)asset.Rotation[2]);
    140                 go.transform.eulerAngles = vector3;
    141         }
    142 }



    unity加载fbx动画 unity动态加载fbx文件_Source

    unity加载fbx动画 unity动态加载fbx文件_json_02

    View Code


    1 Asset.cs类:
     2 using UnityEngine;
     3 using System.Collections.Generic;
     4 public class Asset
     5 {
     6         public const byte TYPE_JSON = 1;
     7         public const byte TYPE_GAMEOBJECT = 2;
     8         public Asset()
     9         {
    10             //default type is gameobject for json load
    11             Type = TYPE_GAMEOBJECT;
    12         }
    13         public byte Type
    14         {
    15             get;
    16             set;
    17         }
    18         public string Name
    19         {
    20             get;
    21             set;
    22         }
    23         public string Source
    24         {
    25             get;
    26             set;
    27         }
    28         public double[] Bounds
    29         {
    30             get;
    31             set;
    32         }
    33        
    34         public double[] Position
    35         {
    36             get;
    37             set;
    38         }
    39         public double[] Rotation
    40         {
    41             get;
    42             set;
    43         }
    44         public List<Asset> AssetList
    45         {
    46             get;
    47             set;
    48         }
    49         public bool isLoadFinished
    50         {
    51             get;
    52             set;
    53         }
    54         public WWW www
    55         {
    56             get;
    57             set;
    58         }
    59         public GameObject gameObject
    60         {
    61             get;
    62             set;
    63         }
    64 }
    65 Scene.cs类:
    66 using System.Collections.Generic;
    67 
    68 public class Scene
    69 {
    70         public List<Asset> AssetList
    71         {
    72             get;
    73             set;
    74         }
    75 }



    生成.unity3d代码:

    unity加载fbx动画 unity动态加载fbx文件_Source

    unity加载fbx动画 unity动态加载fbx文件_json_02

    View Code


    1 using UnityEngine;
     2 using UnityEditor;
     3 using System.IO;
     4 using System;
     5 using System.Text;
     6 using System.Collections.Generic;
     7 using LitJson;
     8 public class BuildAssetBundlesFromDirectory
     9 {
    10       static List<JsonResource> config=new List<JsonResource>();
    11       static Dictionary<string, List<JsonResource>> assetList=new Dictionary<string, List<JsonResource>>();
    12         [@MenuItem("Asset/Build AssetBundles From Directory of Files")]//这里不知道为什么用"@",添加菜单
    13         static void ExportAssetBundles ()
    14         {//该函数表示通过上面的点击响应的函数
    15                    assetList.Clear();
    16                    string path = AssetDatabase.GetAssetPath(Selection.activeObject);//Selection表示你鼠标选择激活的对象
    17                   Debug.Log("Selected Folder: " + path);
    18        
    19        
    20                   if (path.Length != 0)
    21                   {
    22                            path = path.Replace("Assets/", "");//因为AssetDatabase.GetAssetPath得到的是型如Assets/文件夹名称,且看下面一句,所以才有这一句。
    23                             Debug.Log("Selected Folder: " + path);
    24                            string [] fileEntries = Directory.GetFiles(Application.dataPath+"/"+path);//因为Application.dataPath得到的是型如 "工程名称/Assets"
    25                            
    26                            string[] div_line = new string[] { "Assets/" };
    27                            foreach(string fileName in fileEntries)
    28                            {
    29                                     j++;
    30                                     Debug.Log("fileName="+fileName);
    31                                     string[] sTemp = fileName.Split(div_line, StringSplitOptions.RemoveEmptyEntries);
    32                                     string filePath = sTemp[1];
    33                                      Debug.Log(filePath);
    34                                     filePath = "Assets/" + filePath;
    35                                     Debug.Log(filePath);
    36                                     string localPath = filePath;
    37                                     UnityEngine.Object t = AssetDatabase.LoadMainAssetAtPath(localPath);
    38                                    
    39                                      //Debug.Log(t.name);
    40                                     if (t != null)
    41                                     {
    42                                             Debug.Log(t.name);
    43                                             JsonResource jr=new JsonResource();
    44                                             jr.Name=t.name;
    45                                             jr.Source=path+"/"+t.name+".unity3d";
    46                                               Debug.Log( t.name);
    47                                             config.Add(jr);//实例化json对象
    48                                               string bundlePath = Application.dataPath+"/../"+path;
    49                                                if(!File.Exists(bundlePath))
    50                                                 {
    51                                                    Directory.CreateDirectory(bundlePath);//在Asset同级目录下相应文件夹
    52                                                 }
    53                                               bundlePath+="/"  + t.name + ".unity3d";
    54                                              Debug.Log("Building bundle at: " + bundlePath);
    55                                              BuildPipeline.BuildAssetBundle(t, null, bundlePath, BuildAssetBundleOptions.CompleteAssets);//在对应的文件夹下生成.unity3d文件
    56                                     } 
    57                            }
    58                             assetList.Add("AssetList",config);
    59                             for(int i=0;i<config.Count;i++)
    60                             {
    61                                     Debug.Log(config[i].Source);
    62                             }
    63                   }
    64                 string data=JsonMapper.ToJson(assetList);//序列化数据
    65                 Debug.Log(data);
    66         string jsonInfoFold=Application.dataPath+"/../Scenes";
    67         if(!Directory.Exists(jsonInfoFold))
    68         {
    69             Directory.CreateDirectory(jsonInfoFold);//创建Scenes文件夹
    70         }
    71                 string fileName1=jsonInfoFold+"/json.txt";
    72                 if(File.Exists(fileName1))
    73                 {
    74                     Debug.Log(fileName1 +"already exists");
    75                     return;
    76                 }
    77                 UnicodeEncoding uni=new UnicodeEncoding();
    78                   
    79                 using(  FileStream  fs=File.Create(fileName1))//向创建的文件写入数据
    80                 {
    81                         fs.Write(uni.GetBytes(data),0,uni.GetByteCount(data));
    82                         fs.Close();
    83                 }
    84       }
    85 }