unity动态加载远程资源的相关话题网上有一些,但都语焉不详,经过本人的摸索,终于找到门道,记录下来备忘,也分享给同好。



unity动态加载远程资源需要用到unity的一个runtime class,叫做WWW,可以在帮助里面的Scripting中找到。



WWW类有两个重要的方法用来加载远程站点上的资源。



一个是WWW,即直接访问远程文件。例如:



function Start(){
 

        var www : WWW = new WWW("http://yoursite.com/test.jpg"); //开始读取资源,资源你自己改为自己的
 

        yield www;//等待加载完成(不会阻塞其它程序运行)
 

        guiTexture.texture =  www.texture; //将加载的资源直接使用到对象上
 

    }



    见一个GUITexture对象,讲上面的代码复制到一个js脚本中,把这个脚本拖到对象上。点运行,即能看到效果。



    还能用这种方法加载文本、二进制文件等。这时候要用到的是WWW的text和bytes变量,WWW还有一些其他的成员变量,可以参见C:\Program Files\Unity\Editor\Data\Documentation\Documentation\ScriptReference\WWW.html  (假定你的unity安装在默认目录下,mac下类推。当然可以直接在unity的菜单中选help->scripting reference)



 



二是WWW.LoadFromCacheOrDownload



    这是个静态函数,参数为一个url字符串和一个整数的版本号,功能是从url指定的位置下载(如果没有缓存到本地),如果第二次访问相同版本的该资源,则会从本地磁盘的缓存中加载(这对webgame来说是个好消息)。



    下面是用法示例:



 

function Start(){
 

        var www : WWW =  WWW.LoadFromCacheOrDownload("http://yoursite.com/test.unity3d", 1); //加载
 

        yield www;  //等待加载完成
 

        if(www.error != null){//如果出错,则在控制台打印错误
 

            print(www.error);
 

            return;
 

        }
 

        var myAssetBundle =  www.assetBundle; //得到AssetBundle
 

        if(myAssetBundle.Contains("New prefab")){//确认AssetBundle中有指定预置对象
 

            print("ok!");
 

            var ob = myAssetBundle.Load("New prefab");//加载指定预置对象
 

            Instantiate(ob, transform.position, transform.rotation);//实例化该预置对象
 

        }
 

        else 
 

            print("failed.");
 

    }



    向项目中添加一个空对象,然后添加一个js脚本,把上面的内容复制到脚本中,再讲脚本拖到对象上,运行即能看到效果。



接下来问题来了,test.unity3d这个文件哪里来的呢?或者说我们怎么生成我们自己的.unity3d文件呢?这个问题折腾了我很久,现在总算搞明白了一点。



要生成.unity3d文件,需要在项目目录的Asset目录下添加一个Editor目录,然后在这个目录下建立一个js脚本,名字随便取,内容如下:



@MenuItem("Assets/Build AssetBundle From Selection - Track dependencies")
 static function ExportResource () {
  // Bring up save panel
  var path = EditorUtility.SaveFilePanel ("Save Resource", "", "test", "unity3d");
  if (path.Length != 0)
  {
   // Build the resource file from the active selection.
   var selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
   
   BuildPipeline.BuildAssetBundle(Selection.activeObject, selection, path, BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets); 
   Selection.objects = selection;
  }
 } 

@MenuItem("Assets/Build AssetBundle From Selection - No dependency tracking")
 static function ExportResourceNoTrack () {
  // Bring up save panel
  var path = EditorUtility.SaveFilePanel ("Save Resource", "", "test", "unity3d");
  if (path.Length != 0)
  {
   // Build the resource file from the active selection.
   BuildPipeline.BuildAssetBundle(Selection.activeObject, Selection.objects, path);
  }
 }



保存后如果unity不报错,则在你选中project视图中的目录或者对象时,点右键,菜单中会多出两个选项


Build AssetBundle From Selection - Track dependencies
 

Build AssetBundle From Selection - No dependency tracking



当然unity主菜单的Assets中也会多出这两项,这就是上面Editor目录下那个脚本的效果。



选中你要的对象或者目录,点右键,选Build AssetBundle From Selection - Track dependencies



在弹出的文件对话框中设定文件名即可。



 



注意,上面提到了预置对象。这个方法能将预置对象导出到assetbundle中,这是我们最需要的功能。



但是有一个问题,就是assetbundle中不会保存脚本,要想让预置对象(Prefab)的功能完整,则引用这个预置对象的项目中必须有当初做预置对象(Prefab)时用到的脚本!简单点,把原来的脚本文件复制到现在项目中,呵呵……



 



另外还有一个问题,用LoadFromCacheOrDownload加载站点资源需要站点上有crossdomain.xml,这个类似flash的做法。



crossdomain.xml随便在网上找个就好了,找不到的话自己在站点上(我用xampp,存放在hotdocs目录下)自己建一个,内容如下,注意把其中的yoursite改成你的站点名,测试可以直接用ip地址。如果偷懒就直接把 *.yoursite.com改为 *

<?xml version="1.0"?>
 <cross-domain-policy>
    <allow-access-from domain="*.yoursite.com" />
 </cross-domain-policy>