unity动态加载.docx

上传人:b****6 文档编号:6167067 上传时间:2023-01-04 格式:DOCX 页数:13 大小:19.28KB
下载 相关 举报
unity动态加载.docx_第1页
第1页 / 共13页
unity动态加载.docx_第2页
第2页 / 共13页
unity动态加载.docx_第3页
第3页 / 共13页
unity动态加载.docx_第4页
第4页 / 共13页
unity动态加载.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

unity动态加载.docx

《unity动态加载.docx》由会员分享,可在线阅读,更多相关《unity动态加载.docx(13页珍藏版)》请在冰豆网上搜索。

unity动态加载.docx

unity动态加载

用Unity3D制作基于web的网络游戏,不可避免的会用到一个技术-资源动态加载。

比如想加载一个大场景的资源,不应该在游戏的开始让用户长时间等待全部资源的加载完毕。

应该优先加载用户附近的场景资源,在游戏的过程中,不影响操作的情况下,后台加载剩余的资源,直到所有加载完毕。

本文包含一些代码片段讲述实现这个技术的一种方法。

本方法不一定是最好的,希望能抛砖引玉。

代码是C#写的,用到了Json,还有C#的事件机制。

在讲述代码之前,先想象这样一个网络游戏的开发流程。

首先美工制作场景资源的3D建模,游戏设计人员把3D建模导进Unity3D,托托拽拽编辑场景,完成后把每个gameobject导出成XXX.unity3d格式的资源文件(参看BuildPipeline),并且把整个场景的信息生成一个配置文件,xml或者Json格式(本文使用Json)。

最后还要把资源文件和场景配置文件上传到服务器,最好使用CMS管理。

客户端运行游戏时,先读取服务器的场景配置文件,再根据玩家的位置从服务器下载相应的资源文件并加载,然后开始游戏,注意这里并不是下载所有的场景资源。

在游戏的过程中,后台继续加载资源直到所有加载完毕。

一个简单的场景配置文件的例子:

MyDemoSence.txt

Json代码  

{  

  "AssetList":

[{  

      "Name":

"Chair1",  

      "Source":

"Prefabs/Chair001.unity3d",  

      "Position":

[2,0,-5],  

      "Rotation":

[0.0,60.0,0.0]  

  },  

  {  

      "Name":

"Chair2",  

      "Source":

"Prefabs/Chair001.unity3d",  

      "Position":

[1,0,-5],  

      "Rotation":

[0.0,0.0,0.0]  

  },  

  {  

      "Name":

"Vanity",  

      "Source":

"Prefabs/vanity001.unity3d",  

      "Position":

[0,0,-4],  

      "Rotation":

[0.0,0.0,0.0]  

  },  

  {  

      "Name":

"WritingTable",  

      "Source":

"Prefabs/writingTable001.unity3d",  

      "Position":

[0,0,-7],  

      "Rotation":

[0.0,0.0,0.0],  

      "AssetList":

[{  

        "Name":

"Lamp",  

        "Source":

"Prefabs/lamp001.unity3d",  

        "Position":

[-0.5,0.7,-7],  

        "Rotation":

[0.0,0.0,0.0]  

      }]  

  }]  

}  

{

  "AssetList":

[{

      "Name":

"Chair1",

      "Source":

"Prefabs/Chair001.unity3d",

      "Position":

[2,0,-5],

      "Rotation":

[0.0,60.0,0.0]

  },

  {

      "Name":

"Chair2",

      "Source":

"Prefabs/Chair001.unity3d",

      "Position":

[1,0,-5],

      "Rotation":

[0.0,0.0,0.0]

  },

  {

      "Name":

"Vanity",

      "Source":

"Prefabs/vanity001.unity3d",

      "Position":

[0,0,-4],

      "Rotation":

[0.0,0.0,0.0]

  },

  {

      "Name":

"WritingTable",

      "Source":

"Prefabs/writingTable001.unity3d",

      "Position":

[0,0,-7],

      "Rotation":

[0.0,0.0,0.0],

      "AssetList":

[{

        "Name":

"Lamp",

        "Source":

"Prefabs/lamp001.unity3d",

        "Position":

[-0.5,0.7,-7],

        "Rotation":

[0.0,0.0,0.0]

      }]

  }]

}

AssetList:

场景中资源的列表,每一个资源都对应一个unity3D的gameobject

Name:

gameobject的名字,一个场景中不应该重名

Source:

资源的物理路径及文件名

Position:

gameobject的坐标

Rotation:

gameobject的旋转角度

你会注意到WritingTable里面包含了Lamp,这两个对象是父子的关系。

配置文件应该是由程序生成的,手工也可以修改。

另外在游戏上线后,客户端接收到的配置文件应该是加密并压缩过的。

主程序:

C#代码  

  

publicclassMainMonoBehavior:

MonoBehaviour{  

  

  publicdelegatevoidMainEventHandler(GameObjectdispatcher);  

  

  publiceventMainEventHandlerStartEvent;  

  publiceventMainEventHandlerUpdateEvent;  

  

  publicvoidStart(){  

      ResourceManager.getInstance().LoadSence("Scenes/MyDemoSence.txt");  

  

      if(StartEvent!

=null){  

        StartEvent(this.gameObject);  

      }  

  }  

  

  publicvoidUpdate(){  

      if(UpdateEvent!

=null){  

        UpdateEvent(this.gameObject);  

      }  

  }  

}  

  

}  

publicclassMainMonoBehavior:

MonoBehaviour{

  publicdelegatevoidMainEventHandler(GameObjectdispatcher);

  publiceventMainEventHandlerStartEvent;

  publiceventMainEventHandlerUpdateEvent;

  publicvoidStart(){

      ResourceManager.getInstance().LoadSence("Scenes/MyDemoSence.txt");

      if(StartEvent!

=null){

        StartEvent(this.gameObject);

      }

  }

  publicvoidUpdate(){

      if(UpdateEvent!

=null){

        UpdateEvent(this.gameObject);

      }

  }

}

}

这里面用到了C#的事件机制,大家可以看看我以前翻译过的国外一个牛人的文章。

C#事件和Unity3D

在start方法里调用ResourceManager,先加载配置文件。

每一次调用update方法,MainMonoBehavior会把update事件分发给ResourceManager,因为ResourceManager注册了MainMonoBehavior的update事件。

ResourceManager.cs

C#代码  

  

privateMainMonoBehaviormainMonoBehavior;  

privatestringmResourcePath;  

privateScenemScene;  

privateAssetmSceneAsset;  

  

privateResourceManager(){  

  mainMonoBehavior=GameObject.Find("MainCamera").GetComponent();  

  mResourcePath=PathUtil.getResourcePath();  

}  

  

publicvoidLoadSence(stringfileName){  

  mSceneAsset=newAsset();  

  mSceneAsset.Type=Asset.TYPE_JSON;  

  mSceneAsset.Source=fileName;  

  

  mainMonoBehavior.UpdateEvent+=OnUpdate;  

}  

  

privateMainMonoBehaviormainMonoBehavior;

privatestringmResourcePath;

privateScenemScene;

privateAssetmSceneAsset;

privateResourceManager(){

  mainMonoBehavior=GameObject.Find("MainCamera").GetComponent();

  mResourcePath=PathUtil.getResourcePath();

}

publicvoidLoadSence(stringfileName){

  mSceneAsset=newAsset();

  mSceneAsset.Type=Asset.TYPE_JSON;

  mSceneAsset.Source=fileName;

  mainMonoBehavior.UpdateEvent+=OnUpdate;

}

在LoadSence方法里先创建一个Asset的对象,这个对象是对应于配置文件的,设置type是Json,source是传进来的“Scenes/MyDemoSence.txt”。

然后注册MainMonoBehavior的update事件。

C#代码  

publicvoidOnUpdate(GameObjectdispatcher){  

  if(mSceneAsset!

=null){  

      LoadAsset(mSceneAsset);  

      if(!

mSceneAsset.isLoadFinished){  

        return;  

      }  

  

      //clearmSceneandmSceneAssetfornextLoadSencecall  

      mScene=null;  

      mSceneAsset=null;  

  }  

  

  mainMonoBehavior.UpdateEvent-=OnUpdate;  

}  

publicvoidOnUpdate(GameObjectdispatcher){

  if(mSceneAsset!

=null){

      LoadAsset(mSceneAsset);

      if(!

mSceneAsset.isLoadFinished){

        return;

      }

      //clearmSceneandmSceneAssetfornextLoadSencecall

      mScene=null;

      mSceneAsset=null;

  }

  mainMonoBehavior.UpdateEvent-=OnUpdate;

}

OnUpdate方法里调用LoadAsset加载配置文件对象及所有资源对象。

每一帧都要判断是否加载结束,如果结束清空mScene和mSceneAsset对象为下一次加载做准备,并且取消update事件的注册。

最核心的LoadAsset方法:

C#代码  

privateAssetLoadAsset(Assetasset){  

  

  stringfullFileName=mResourcePath+"/"+asset.Source;  

    

  //ifwwwresourceisnew,setintowwwcache  

  if(!

wwwCacheMap.ContainsKey(fullFileName)){  

      if(asset.www==null){  

        asset.www=newWWW(fullFileName);  

        returnnull;  

      }  

  

      if(!

asset.www.isDone){  

        returnnull;  

      }  

      wwwCacheMap.Add(fullFileName,asset.www);  

  }  

  

privateAssetLoadAsset(Assetasset){

  stringfullFileName=mResourcePath+"/"+asset.Source;

  

  //ifwwwresourceisnew,setintowwwcache

  if(!

wwwCacheMap.ContainsKey(fullFileName)){

      if(asset.www==null){

        asset.www=newWWW(fullFileName);

        returnnull;

      }

      if(!

asset.www.isDone){

        returnnull;

      }

      wwwCacheMap.Add(fullFileName,asset.www);

  }

传进来的是要加载的资源对象,先得到它的物理地址,mResourcePath是个全局变量保存资源服务器的网址,得到fullFileName类似1和Chair2用到了同一个资源Chair001.unity3d,加载Chair2的时候就不需要下载了。

如果当前帧没有加载完毕,返回null等到下一帧再做判断。

这就是WWW类的特点,刚开始用WWW下载资源的时候是不能马上使用的,要等待诺干帧下载完成以后才可以使用。

可以用yield返回www,这样代码简单,但是C#要求调用yield的方法返回IEnumerator类型,这样限制太多不灵活。

继续LoadAsset方法:

C#代码  

  

  if(asset.Type==Asset.TYPE_JSON){//Json  

      if(mScene==null){  

        stringjsonTxt=mSceneAsset.www.text;  

        mScene=JsonMapper.ToObject(jsonTxt);  

      }  

        

      //loadscene  

      foreach(AssetsceneAssetinmScene.AssetList){  

        if(sceneAsset.isLoadFinished){  

          continue;  

        }else{  

          LoadAsset(sceneAsset);  

          if(!

sceneAsset.isLoadFinished){  

              returnnull;  

          }  

        }  

      }  

  }  

  

  if(asset.Type==Asset.TYPE_JSON){//Json

      if(mScene==null){

        stringjsonTxt=mSceneAsset.www.text;

        mScene=JsonMapper.ToObject(jsonTxt);

      }

      

      //loadscene

      foreach(AssetsceneAssetinmScene.AssetList){

        if(sceneAsset.isLoadFinished){

          continue;

        }else{

          LoadAsset(sceneAsset);

          if(!

sceneAsset.isLoadFinished){

              returnnull;

          }

        }

      }

  }

代码能够运行到这里,说明资源都已经下载完毕了。

现在开始加载处理资源了。

第一次肯定是先加载配置文件,因为是Json格式,用JsonMapper类把它转换成C#对象,我用的是LitJson开源类库。

然后循环递归处理场景中的每一个资源。

如果没有完成,返回null,等待下一帧处理。

继续LoadAsset方法:

C#代码  

  

  elseif(asset.Type==Asset.TYPE_GAMEOBJECT){//Gameobject  

      if(asset.gameObject==null){  

        wwwCacheMap[fullFileName].assetBundle.LoadAll();  

        GameObjectgo=(GameObject)GameObject.Instantiate(wwwCacheMap[fullFileName].assetBundle.mainAsset);  

        UpdateGameObject(go,asset);  

        asset.gameObject=go;  

      }  

  

      if(asset.AssetList!

=null){  

        foreach(AssetassetChildinasset.AssetList){  

          if(assetChild.isLoadFinished){  

              continue;  

          }else{  

              AssetassetRet=LoadAsset(assetChild);  

              if(assetRet!

=null){  

                assetRet.gameObject.transform.parent=asset.gameObject.transform;  

              }else{  

                returnnull;  

              }  

          }  

        }  

     

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 家庭教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1