【Unity】资源加载方式大全

目录

一、Assets序列化和反序列化

二、Xml序列化和反序列化

三、二进制形式序列化和反序列化

四、AssetBundle


一、Assets序列化和反序列化

/// <summary>
/// 使用如下特性即可在Create->找到CreateAssets菜单,创建一个Assets可格式化的存储文件
/// </summary>
[CreateAssetMenu(fileName = "TestAssets", menuName = "CreateAssets", order = 0)]
public class AssetsSerialize : ScriptableObject
{
    public int Id;
    public string Name;
    public List<string> TestList;
}

   /// <summary>
    /// 读取.asset文件
    /// </summary>
    void ReadTestAssets()
    {
        AssetsSerialize assets = UnityEditor.AssetDatabase.LoadAssetAtPath<AssetsSerialize>("Assets/Scripts/MyTestAssets.asset");
        Debug.Log(assets.Id);
        Debug.Log(assets.Name);
        foreach(var v in assets.TestList)
        {
            Debug.Log(v);
        }
    }

二、Xml序列化和反序列化

    [System.Serializable]
    public class TestSerialize {

        [XmlAttribute("Id")]
        public int Id { get; set; }

        [XmlAttribute("Name")]//单属性int string bool float double ...
        public string Name { get; set; }

        [XmlElement("List")] //[XmlArray("List")] 数组 列表
        public List<int> List { get; set; }
    }

    void SerializeTest()
    {
        TestSerialize testSerialize = new TestSerialize();
        testSerialize.Id = 1;
        testSerialize.Name = "test";
        testSerialize.List = new List<int>();
        testSerialize.List.Add(2);
        testSerialize.List.Add(3);
        XmlSerialize(testSerialize);
    }

    /// <summary>
    /// 序列化xml
    /// </summary>
    /// <param name="testSerialize"></param>
    void XmlSerialize(TestSerialize testSerialize)
    {
        //文件流
        FileStream fileStream = new FileStream(Application.dataPath + "/test.xml", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
        //写入流
        StreamWriter sw = new StreamWriter(fileStream, System.Text.Encoding.UTF8);
        //创建testSerialized同类型的Xml序列化对象
        XmlSerializer xml = new XmlSerializer(testSerialize.GetType());
        //使用xml序列化testSerialized对象存入sw指定的文件流
        xml.Serialize(sw, testSerialize);
        //关闭写入流
        sw.Close();
        //关闭文件流
        fileStream.Close();
    }

    /// <summary>
    /// 反序列化xml
    /// </summary>
    /// <returns></returns>
    TestSerialize XmlDeSerialize()
    {
        FileStream fs = new FileStream(Application.dataPath + "/test.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
        XmlSerializer xs = new XmlSerializer(typeof(TestSerialize));
        TestSerialize testSerialize = (TestSerialize)xs.Deserialize(fs);
        fs.Close();
        return testSerialize;
    }

三、二进制形式序列化和反序列化

 /// <summary>
    /// 将对象序列化为二进制文件
    /// </summary>
    /// <param name="testSerialize"></param>
    void BinarySerialize(TestSerialize testSerialize)
    {
        //创建二进制文件
        FileStream fs = new FileStream(Application.dataPath + "/test.bytes", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);        
        BinaryFormatter bf = new BinaryFormatter();
        //序列化testSerialize保存入fs指定文件
        bf.Serialize(fs, testSerialize);
        //关闭流
        fs.Close();
    }

    /// <summary>
    /// 二进制文件反序列化
    /// </summary>
    /// <returns></returns>
    TestSerialize BinaryDeserialize()
    {
        //使用编辑器加载方式二进制文件
        TextAsset textAsset = UnityEditor.AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/test.bytes");
        //缓存流(将二进制文件缓存入缓存区域)
        MemoryStream stream = new MemoryStream(textAsset.bytes);
        //使用BinaryFormatter反序列化二进制文件
        BinaryFormatter bf = new BinaryFormatter();
        TestSerialize ts = (TestSerialize)bf.Deserialize(stream);
        //关闭流
        stream.Close();
        return ts;
    }

四、AssetBundle

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class BundleEditor{

    [MenuItem("Tools/打包!")]
    public static void Build()
    {
        //注意:StreamingAssets文件夹需手动创建
        //参数:打包路径(Assets/StreamingAssets文件夹)、打包方式、打包平台(运行平台)
        BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.ChunkBasedCompression,
            EditorUserBuildSettings.activeBuildTarget);

        //刷新编辑器
        AssetDatabase.Refresh();
    }

}

上面这个文件是编辑器文件,放在Editor文件夹下(自己建立个Editor文件夹)

准备打包的对象如下随便找个预制体,设置AssetBundle名称

同时这个预制体 身上的所有依赖组件都必须打包,才可以让预制体通过AB包加载出来时是正常的,这里我这个Cube还用了M1材质球,打包出来后StreamingAssets会对应地出现文件,最关键的是要看懂这下面2个图

这是apple包的manifest文件内容,真正程序要加载的是没有后缀的,名为apple的文件,真正程序要加载的是没有后缀的,名为apple的文件,真正程序要加载的是没有后缀的,名为apple的文件(这一点要清楚,所以我说3次)

可见有Assets下面有2个预制体文件路径,这表明这个AB包有2个预制体,而依赖文件是m1和m2。

在要使用到Spp或者Cqq之前,要先加载完成依赖文件才能让资源显示正常,下面给出比较通用的加载方法。

 Dictionary<string, GameObject> resourcesDict = new Dictionary<string, GameObject>();
    void Start()
    {
        GameObject goPrefab = LoadResourceByResourceNameFromAb("apple", "Cqq");
        if (goPrefab != null)
        {
            GameObject go = GameObject.Instantiate(goPrefab);
        }
    }

    private GameObject LoadResourceByResourceNameFromAb(string abName, string resourceName)
    {
        if (!resourcesDict.ContainsKey(abName + "|" + resourceName))
        {
            //加载ab包 本地加载方式 一个名为apple的ab包文件
            AssetBundle assetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + abName);
            if (assetBundle != null)
            {
                //加载源资源时先加载依赖资源
                //1.加载位于StreamingAssets目录下的StreamingAssets包
                AssetBundle streamingAssetsBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/StreamingAssets");
                if (streamingAssetsBundle == null)
                {
                    Debug.Log("streamingAssetsBundle is not exist!");
                    return null;
                }
                //加载StreamingAssets包下的AssetBundleManifest文件(可打开StreamingAssets.manifest文件看第三行的名字就是它)
                AssetBundleManifest assetBundleManifest = streamingAssetsBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
                //获取abName包的全部依赖名称!即StreamingAssets.manifest文件的指定Info为abName的Dependencies的数组内容
                string[] deps = assetBundleManifest.GetAllDependencies(abName);
                //加载abName包的全部依赖资源
                for(int i=0;i< deps.Length; i++)
                {
                    //Debug.Log("依赖资源名称" + deps[i]);
                    //因为依赖名称是一个相对路径,例如:StreamingAssets下的pp文件夹的m2资源是写为 pp/m2,所以加载是没问题
                    AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + deps[i]);
                }
                //加载源资源
                GameObject go = assetBundle.LoadAsset<GameObject>(resourceName);
                if (go != null)
                {
                    resourcesDict.Add(abName + "|" + resourceName, go);
                    return go;
                }                
                else
                {
                    Debug.LogWarning("abNmae:" + abName + ",resourceName:" + resourceName + " is not exist!");
                    return null;
                }
            }
            else
            {
                Debug.LogWarning("abNmae:" + abName + " is not exist!");
                return null;
            }
        }
        else
        {
            GameObject go = null;
            resourcesDict.TryGetValue(abName + "|" + resourceName, out go);
            return go;
        }
    }

注意:我加载AB包的全部依赖资源的方式,是通过StreamingAssets包的manifest文件获取该AB包的全部依赖资源名称的。

StreamingAssets包是自动生成的,它也是位于StreamingAssets文件夹下,内容如下:

可见apple包有2个依赖分别为m1和pp/m2 注意这里是相对于StreamingAssets的依赖资源包路径。

所以上面代码的加载方式是可以这么写的,这个pp/m2是怎么产生的呢?其实AssetBundle如下就会自动生成。

上面代码缺点有很多,

问题一:当我 加载了apple包的Cqq后,就已经加载了一次apple包的全部 依赖资源m1和pp/m2都加载了,但是Cqq只用pp/m2 ,不需要m1,这就是加载了多余的依赖资源,所以我们最好将Cqq和Spp预制体分开2个包打包比较合适,也就是将依赖于不同资源的资源分开打包,将依赖于同样资源的资源一起打包,多余加载问题。

问题二:重复加载问题,上面的代码当我加载一次apple包内的Cqq预制体后,apple包的全部依赖资源都加载过了,当第二次加载apple包的Spp预制体时,我又再次去加载了apple包的全部依赖资源。。很傻吧这操作。。怎么解决我想可能就是加个标志位去判断,这个ab包的依赖资源是否已被加载过,这样,还没真正考虑那么详细,百度可能有人写过这样的解决方法吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值