Unity游戏开发——新发教你做游戏(三):3种资源加载方式

一、前言

文章列表
Unity游戏开发——新发教你做游戏(一):打开游戏开发新世界的大门
Unity游戏开发——新发教你做游戏(二):60个Unity免费资源获取网站
Unity游戏开发——新发教你做游戏(三):3种资源加载方式
Unity游戏开发——新发教你做游戏(四):角色移动控制
Unity游戏开发——新发教你做游戏(五):导航系统Navigation
Unity游戏开发——新发教你做游戏(六):教你2个步骤实现摇杆功能
Unity游戏开发——新发教你做游戏(七):Animator控制角色动画播放
在这里插入图片描述
本工程Demo我已上传到GitHub,感兴趣的同学可以下载下来学习。
GitHub工程地址:https://github.com/linxinfa/Unity-RpgGameDemo
在这里插入图片描述
嗨,大家好,我是新发,上一篇文章我们讲了资源的获取,我们有了美术资源之后,导入Unity中,就需要通过程序来加载和管理资源,本文我将介绍资源加载的三种方式。

二、Unity的目录结构规范

第一个问题,我们的资源放在什么目录中?那么,就需要先知道Unity的目录结构。
Assets为主目录,其他所有文件都在Assets目录下,如下,这是我的目录结构,也建议大家在创建工程时就养成规范目录的习惯,不然项目后期必定返工整理目录和文件规范。
在这里插入图片描述
以上,和游戏资源相关的目录是四个:ResourcesRawAssetsGameResStreamingAssets

关于Unity的目录文件操作,我之前写过一篇文章:https://blog.csdn.net/linxinfa/article/details/51679528

为了方便理清关系,我画了下面这个图。
在这里插入图片描述

1、Resources(不是很推荐把资源放这个目录)

只读文件;资源全部被无条件被打进包内;这个文件夹下的资源将被加密和压缩打包;通过Resoureces.Load方式加载。
Demo演示,可以直接把资源放这个目录,如果是实战项目,建议将资源打成AssetBundle放在StreamingAssets目录或服务器中,方便热更资源。

2、RawAssets(存放生资源)

RawAssets不是Unity默认的文件夹,所以文件夹名字没有严格要求一定要叫RawAssets
什么是生资源呢?生就是未加工的意思,大家应该听过生肉、熟肉,嘿嘿。
生资源,比如一个角色模型,我们一般是包装成预设,一个成品预设。这个预设依赖了网格、动画、材质球和贴图等资源,这些被成品依赖的零件就是生资源。
RawAssets中的生资源,被依赖性得打进包内,比如,成品预设放在Resources目录中,那么成品依赖的对应的生资源就会被打进包内了,当然,如果没有被任何成品预设依赖,那么对应的生资源就不会被打进包内了。

3、GameRes(存放熟资源)

相对应与生资源,我们加工好的成品资源就是熟资源。在Editor环境下,直接通过AssetDatabase.LoadAssetAtPah同步加载资源。发布的时候,我们将GameRes中的资源打成AssetBundle放到StreamingAssets目录中,当需要资源热更的时候,我们将新打的AssetBundle放到远程服务器上,客户端下载到本地的Application.persistentDataPath沙箱目录,再通过AssetBundle.LoadFromFile同步加载。
加载资源的时候,优先去Application.persistentDataPath中找,如果没有才去StreamingAssets中找。

4、StreamingAssets(存放AssetBundle)

StreamingAssets文件夹是一个只读的文件夹,但是它和Resources有点区别,Resources文件夹下的资源会进行一次压缩,而且也会加密,不使用点特殊办法是拿不到原始资源的。但是StreamingAssets文件夹就下面的所有资源不会被加密,是原封不动的打包到发布包中,这样很容易就拿到里面的文件。我们打AssetBundle的时候建议自己做一次加密。
我们可以通过WWWUnityWebRequest异步加载资源,也可以通过AssetBundle.LoadFromFile同步加载资源。

5、其他目录
5.1、Editor目录(存放编辑器的扩展脚本)

所有资源文件或者脚本文件都不会被打进发布包中,并且脚本也只能在编辑时使用。
工具类的脚本放在这里,或者是一些编辑时用的DLL

5.2、Scripts目录 (存放脚本)

我们的c#游戏脚本放在这个目录中,注意,如果是编辑器工具类的c#脚本,则放在Editor目录中。

5.3、Scenes目录 (存放场景)

我们的场景文件放在这个目录中,包括场景的Lighting灯光烘焙数据、Navigation导航数据等。

5.4、Plugins目录(SDK依赖的库文件)

项目中很可能需要接一些第三方SDK,比如微信开放平台的SDK,对应的SDK库文件就是放这个目录中(子目录Plugins/AndroidPlugins/iOS)。还有你可能会用到一些第三方库,比如HoTween.dllZxing.dllIonic.Zip.Unity.dll等,都是放在Plugins中。

5.5、Shaders目录(存放shader脚本)

shader一般是技术美术来写。Unity2018推出了ShaderGraph,我之前写了一篇关于ShaderGraph的实战文章,大家有兴趣可以看看:https://blog.csdn.net/linxinfa/article/details/108049048

三、3种资源加载方式

1、编辑器环境下加载GameRes目录中的资源

在编辑器环境下,直接使用这种方式加载资源。
比如加载Assets/GameRes/Cube.prefab
注意,这种方式只能在编辑器环境下使用。

//using UnityEditor;
#if UNITY_EDITOR
string resPath = "Assets/GameRes/Cube.prefab";
//加载预设
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(resPath);
//实例化预设
GameObject go = Instantiate<GameObject>(prefab);
#endif
2、加载Resources目录中的资源

Resources目录中的资源,通过Resources.Load同步加载。
比如加载Assets/Resources/Cube.prefab

//加载预设,注意不用带.prefab后缀
GameObject prefab = Resources.Load<GameObject>("Cube");
//实例化预设
GameObject go = Instantiate<GameObject>(prefab);
3、移动平台加载StreamingAssets目录中的资源

一般我们是将GameRes目录中的资源打成AssetBundle放在StreamingAssets目录中,然后通过WWWUnityWebRequest异步加载,或者通过AssetBundle.LoadFromFile同步加载。

3.1、设置资源的AssetBundle名

首先,对资源设置AssetBunle名称,建议以所在目录为名称,比如下图中的CubeSphere两个预设,都设置成3dprefabs
在这里插入图片描述
如果资源比较多,建议写个Editor工具执行自动化设置。

using UnityEngine;
using UnityEditor;
using System.IO;

public class BuildTools
{
    [MenuItem("Tools/SetABName")]
    public static void SetABName()
    {
        //移除没有用的assetbundlename
        AssetDatabase.RemoveUnusedAssetBundleNames();
#if UNITY_STANDALONE_WIN
        string dataPath = Application.dataPath.Replace("/", "\\");
        string gameResPath = Path.Combine(dataPath, "GameRes\\");
#else
        string dataPath = Application.dataPath;
        string gameResPath = Path.Combine(dataPath, "GameRes/");
#endif
        string[] files = Directory.GetFiles(gameResPath, "*.*", SearchOption.AllDirectories);
        foreach (string filePath in files)
        {
            if (filePath.EndsWith(".meta")) continue;
            string fullPath = filePath;
#if UNITY_STANDALONE_WIN
            fullPath = filePath.Replace("/", "\\");
#endif

            string fileFullDirName = Path.GetDirectoryName(fullPath);
            string fileAssetDirName = fullPath.Replace(dataPath, "Assets");
            string abName = fileFullDirName.Replace(gameResPath, "");
#if UNITY_STANDALONE_WIN
            if (abName.Contains("\\"))
                abName = abName.Substring(0, abName.IndexOf("\\"));
#else
            if (abName.Contains("/"))
                abName = abName.Substring(0, abName.IndexOf("/"));
#endif
            AssetImporter importer = AssetImporter.GetAtPath(fileAssetDirName);
            importer.assetBundleName = abName;
        }
        Debug.Log("SetABName Done");
    }
}
3.2、AssetBundle打包

接着,通过BuildPipeline.BuildAssetBundles进行AssetBundle打包。

using UnityEngine;
using UnityEditor;
using System.IO;

public class BuildTools
{
    [MenuItem("Tools/BuildAB")]
    public static void StartBuildAB()
    {
    	// 第3个参数根据你的平台而定
        BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, 
        								BuildAssetBundleOptions.ChunkBasedCompression, 
        								BuildTarget.StandaloneWindows);
        AssetDatabase.Refresh();
    }
}

AssetBundle成功,即可在StreamingAssets目录中看到了
在这里插入图片描述

3.3、AssetBundle加载

接下来是游戏运行时加载AssetBundle,比如我们想加载3dprefabs这个AssetBundle中的Cube
方法一:AssetBundle.LoadFromFile同步加载(推荐)

//加载AssetBundle
string abResPath = Path.Combine(Application.streamingAssetsPath, "3dprefabs");
AssetBundle ab = AssetBundle.LoadFromFile(abResPath);
//加载Asset
GameObject prefab = ab.LoadAsset<GameObject>("Cube");
//实例化
GameObject cube = Instantiate<GameObject>(prefab);

方法二:UnityWebRequest异步加载(支持服务器上在资源加载)

IEnumerator LoadAsset()
{
	//注意:本地目录需要加上"file://"
    string uri = "file://" + Application.streamingAssetsPath + "/3dprefabs";
    UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri, 0);
    yield return request.SendWebRequest();
    if (request.isNetworkError)
    {
        Debug.LogError(request.error);
    }
    //获取到ab包
    AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
    //加载Asset
    GameObject prefab = ab.LoadAsset<GameObject>("Cube");
    //实例化
    GameObject go = Instantiate<GameObject>(prefab);
}

方法三:WWW异步加载(支持服务器上在资源加载,已过时)

IEnumerator LoadAsset()
{
	//注意:本地目录需要加上"file://"
    string uri = "file://" + Application.streamingAssetsPath + "/3dprefabs";
    WWW www = new WWW(uri);
    yield return www;
    //获取到ab包
    AssetBundle ab = www.assetBundle;
    //加载Asset
    GameObject prefab = ab.LoadAsset<GameObject>("Cube");
	//实例化
    GameObject go = Instantiate<GameObject>(prefab);
}

四、资源热更

项目上线后,很可能需要热更游戏资源,这个时候,就需要从服务器端下载AssetBundle到本地目录:Application.persistentDataPath
关于如何下载文件,参见我之前这篇文章:
https://blog.csdn.net/linxinfa/article/details/94436027

加载资源的时候,优先去Application.persistentDataPath找看看有没有对应的资源,如果有,已Application.persistentDataPath中的资源为准,否则,再去Application.streamingAssets目录中找资源。

//你的资源文件
string resName = System.IO.Path.Combine(Application.persistentDataPath, "你的资源文件名");
if(System.IO.File.Exists(resName))
{
	//在Application.persistentDataPath目录中加载资源	
}
else
{
	//在Application.streamingAssets目录中加载资源
}

也有一些人是在游戏首次启动时将Application.streamingAssets目录中的所有AssetBundle拷贝到Application.persistentDataPath目录中,后面如果有资源热更,就会覆盖Application.persistentDataPath目录中的资源,加载资源统一在Application.persistentDataPath中找。

  • 53
    点赞
  • 195
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林新发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值