Unity的WWW网络动态加载和储存在本地

17 篇文章 0 订阅

     在平时的软件发中需要从服务器上加载一下资源包,场景时,我们需要使用Unity的WWW加载方法进行图片加载。最近研究WWW加载发现很多问题和报错,这里接写出来和大家共享一下。

  关于加载:首先是检查本地文件里是否存在相同的资源包文件(检查和校验版本号),如果都是正确的就不需要从服务器端下载了直接从本地(手机就是SD卡里了)加载就可以了。

  首先需要去比较服务器段的版本和客户端的文件是否相同,如果不同那么就要下载最新版本的资源了,同时还要把老版本的从本地删除,不然在手机里会很占储存空间的。

  新建一个Resource类,作为加载工具类继承与MonoBehaviour。

  新建方法,传入必要信息提供加载:

  System.IO包里提供了一个File类,其Exists方法就是查询指定路径下是否有指定的文件存在。

public static string suffix = ".unity3d";//资源包后缀
 
public static Dictionary<string,GameObject> cache = new Dictionary<string, GameObject>();
 
public void load(string path,string name,int version){
 
if(!File.Exists(Application.persistentDataPath + name + suffix + version)){
 
StartCoroutine(loader(path,name,version));//网络加载
 
}else{
 
StartCoroutine(loadBundleFromLocal(path,name,version)); //本地加载
 
}
}

在加载时需要启动一个协程,异步加载。如果加载成功则就写入本地和内存里方便调用,如果有新的版本则需要吧老版本的删除掉。

private IEnumerator loadBundle(string path,string name,int version){
 
int oldVersion = version - 1;//写死了
 
string pathName = Application.persistentDataPath + path + name;
 
string url = path + name + suffix;
 
using(WWW www =new WWW(url)){
 
yield return www;
 
if(www.error == null){
 
if(File.Exists(pathName + oldVersion)){
 
File.Delete(pathName + oldVersion);
 
Debug.Log("delete old version data succeed...");
 
}
 
if(!File.Exists(pathName + version)){
 
File.WriteAllBytes(pathName + version,www.bytes);
 
Debug.Log("load bundle succeed,write file path:"+pathName + version);
 
}else{
 
Debug.Log("write file error...");
 
}
 
AssetBundle ab = www.assetBundle;
 
GameObject go = ab.mainAsset as GameObject;
 
cache[name] = go;
 
Resource.go = go;
 
//ab.Unload(false);
 
}
 
}
 
}
 从本地加载就更简单了,直接把本地文件所在的路径传给WWW作为参数就可以了。

private IEnumerator loadBundleFromLocal(string path,string name,int version){
 
using(WWW www = new WWW("file:///"+Application.persistentDataPath + path + name + version)){
 
yield return www;
 
if(www.error == null){
 
AssetBundle ab = www.assetBundle;
 
GameObject go = ab.mainAsset as GameObject;
 
cache[name] = go;
 
Resource.go = go;
 
Debug.Log("load data frome local succeed...");
 
}
 
}
 
}

好了,Resource这个类就基本建立完成了。准备调用~

一般我们是这么写的:

using UnityEngine;
 
using System.Collections;
 
public class LoadUIResponse : MonoBehaviour {
 
public Resource rs;
 
void Start(){
 
if(rs == null){
 
rs = new Resource();
 
}
 
int version = 1;
 
rs.load("http://192.168.1.122/resource/","monster1",version);
 
}
 
}

但是在运行时会报出异常:NullReferenceException UnityEngine.MonoBehaviour.StartCoroutine (IEnumerator routine)。

  这是咋回事,原来我的Resource是继承与MonoBehaviour的。看看这个警告:

  You are trying to create a MonoBehaviour using the 'new' keyword.  This is not allowed.  MonoBehaviours can only be added using AddComponent().  Alternatively, your script can inherit from ScriptableObject or no base class at all

  UnityEngine.MonoBehaviour:.ctor()

  这就要注意了,这个Resource不能用new。是需要加在一个显示组件上通过AddComponent()方法来获取的。

  因此正确做法如下:

  在响应组件上添加Resource脚本,和UIResponse脚本。

  在UIResponse上添加代码:

private Resource rs;
 
string path ="";   
int version = 1;
 
string name = "monster1";
 
void start(){
 
rs = gameObject.GetComponent(typeof(Resource)) as Resource;
 
Resource.instance = rs;
 
}
 
void OnMouseDown(){
 
Resource.instance.load(path,name,version);
 
}

这样,随着游戏的初始化,加载工具类Resource就被初始化出来了,并且已经存放在Resource的instance变量里。以后就可以直接使用Resource.instance来调用加载了。

  并且已有的加载都储存在cache里了,也可以先根据name到内存里去查找一遍再去加载。

  最终加载出来的gameObject需要Instantiate实例化出来。

  以后就可以直接使用Resource.instance来访问Resource里的个个加载方法了。

  Resource的instance的get/set方法的写法如下:
private static Resource _instance;
 
//添加get和set
 
public static Resource instance{
 
set {
 
_instance = value;
 
}
 
get {
 
if (_instance == null) {
 
//_instance = new Resource();
 
Debug.Log("no instance.");
 
}
 
return _instance;
 
}
 
}
看起来和单例的创建方法很类似,如果直接使用调用单例的方式来调用的话。执行到建立协程StartCoroutine时就会抛出空引用的异常,并出现不能创建新的MonoBehaviour实例的警告。




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中,你可以使用Android的Java API来读取本地图片。以下是一个简单的示例: 1. 首先,创建一个C#脚本,用于调用Java API: ```csharp using UnityEngine; using System.Collections; public class AndroidGallery : MonoBehaviour { private AndroidJavaObject galleryActivity; void Start () { // 获取GalleryActivity类的引用 galleryActivity = new AndroidJavaObject("com.example.gallery.GalleryActivity"); } public void OpenGallery() { // 调用GalleryActivity类中的OpenGallery方法 galleryActivity.Call("OpenGallery"); } public void SetImage(string path) { // 调用GalleryActivity类中的SetImage方法 galleryActivity.Call("SetImage", path); } } ``` 2. 然后,在Android项目中创建一个名为GalleryActivity的Java类: ```java package com.example.gallery; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; public class GalleryActivity extends Activity { private static final int SELECT_PICTURE = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } public void OpenGallery() { Intent intent = new Intent(Intent.ACTION_PICK); intent.setType("image/*"); startActivityForResult(intent, SELECT_PICTURE); } public void SetImage(String path) { // 在Unity中调用SetImage方法时,将图片路径传递给该方法 Intent intent = new Intent(); intent.setData(Uri.parse(path)); setResult(Activity.RESULT_OK, intent); finish(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SELECT_PICTURE && resultCode == RESULT_OK) { String path = data.getDataString(); // 将图片路径返回给Unity SetImage(path); } } } ``` 3. 最后,在Unity中使用AndroidGallery脚本来加载本地图片: ```csharp using UnityEngine; using UnityEngine.UI; using System.Collections; public class LoadImage : MonoBehaviour { public RawImage image; void Start () { // 创建AndroidGallery对象 AndroidGallery androidGallery = new AndroidGallery(); // 在Android设备上打开相册 androidGallery.OpenGallery(); } void Update () { // 检查是否有新的图片被选择 if (Input.GetKeyDown(KeyCode.Escape)) { string path = PlayerPrefs.GetString("ImagePath"); if (path != "") { // 加载本地图片 StartCoroutine(LoadLocalImage(path)); } } } IEnumerator LoadLocalImage(string path) { WWW www = new WWW("file://" + path); yield return www; // 将加载的图片显示在RawImage组件中 image.texture = www.texture; } } ``` 在上面的示例中,我们通过AndroidGallery脚本打开了Android设备上的相册,然后在GalleryActivity类中选择了一张图片,并将其路径传递给了Unity。在Unity中,我们使用PlayerPrefs来存储图片路径,并使用WWW类来加载本地图片。最后,我们将加载的图片显示在RawImage组件中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值