赞
踩
文章列表
Unity游戏开发——新发教你做游戏(一):打开游戏开发新世界的大门
Unity游戏开发——新发教你做游戏(二):60个Unity免费资源获取网站
Unity游戏开发——新发教你做游戏(三):3种资源加载方式
Unity游戏开发——新发教你做游戏(四):角色移动控制
Unity游戏开发——新发教你做游戏(五):导航系统Navigation
Unity游戏开发——新发教你做游戏(六):教你2个步骤实现摇杆功能
Unity游戏开发——新发教你做游戏(七):Animator控制角色动画播放
本工程Demo
我已上传到GitHub
,感兴趣的同学可以下载下来学习。
GitHub
工程地址:https://github.com/linxinfa/Unity-RpgGameDemo
嗨,大家好,我是新发,上一篇文章我们讲了资源的获取,我们有了美术资源之后,导入Unity
中,就需要通过程序来加载和管理资源,本文我将介绍资源加载的三种方式。
第一个问题,我们的资源放在什么目录中?那么,就需要先知道Unity
的目录结构。
Assets
为主目录,其他所有文件都在Assets
目录下,如下,这是我的目录结构,也建议大家在创建工程时就养成规范目录的习惯,不然项目后期必定返工整理目录和文件规范。
以上,和游戏资源相关的目录是四个:Resources
、RawAssets
、GameRes
、StreamingAssets
。
关于
Unity
的目录文件操作,我之前写过一篇文章:https://blog.csdn.net/linxinfa/article/details/51679528
为了方便理清关系,我画了下面这个图。
只读文件;资源全部被无条件被打进包内;这个文件夹下的资源将被加密和压缩打包;通过Resoureces.Load
方式加载。
做Demo
演示,可以直接把资源放这个目录,如果是实战项目,建议将资源打成AssetBundle
放在StreamingAssets
目录或服务器中,方便热更资源。
RawAssets
不是Unity
默认的文件夹,所以文件夹名字没有严格要求一定要叫RawAssets
。
什么是生资源呢?生就是未加工的意思,大家应该听过生肉、熟肉,嘿嘿。
生资源,比如一个角色模型,我们一般是包装成预设,一个成品预设。这个预设依赖了网格、动画、材质球和贴图等资源,这些被成品依赖的零件
就是生资源。
RawAssets
中的生资源,被依赖性得打进包内,比如,成品预设放在Resources
目录中,那么成品依赖的对应的生资源就会被打进包内了,当然,如果没有被任何成品预设依赖,那么对应的生资源就不会被打进包内了。
相对应与生资源,我们加工好的成品资源就是熟资源。在Editor
环境下,直接通过AssetDatabase.LoadAssetAtPah
同步加载资源。发布的时候,我们将GameRes
中的资源打成AssetBundle
放到StreamingAssets
目录中,当需要资源热更的时候,我们将新打的AssetBundle
放到远程服务器上,客户端下载到本地的Application.persistentDataPath
沙箱目录,再通过AssetBundle.LoadFromFile
同步加载。
加载资源的时候,优先去Application.persistentDataPath
中找,如果没有才去StreamingAssets
中找。
StreamingAssets
文件夹是一个只读的文件夹,但是它和Resources
有点区别,Resources
文件夹下的资源会进行一次压缩,而且也会加密,不使用点特殊办法是拿不到原始资源的。但是StreamingAssets
文件夹就下面的所有资源不会被加密,是原封不动的打包到发布包中,这样很容易就拿到里面的文件。我们打AssetBundle
的时候建议自己做一次加密。
我们可以通过WWW
或UnityWebRequest
异步加载资源,也可以通过AssetBundle.LoadFromFile
同步加载资源。
所有资源文件或者脚本文件都不会被打进发布包中,并且脚本也只能在编辑时使用。
工具类的脚本放在这里,或者是一些编辑时用的DLL
。
我们的c#
游戏脚本放在这个目录中,注意,如果是编辑器工具类的c#
脚本,则放在Editor
目录中。
我们的场景文件放在这个目录中,包括场景的Lighting
灯光烘焙数据、Navigation
导航数据等。
项目中很可能需要接一些第三方SDK
,比如微信开放平台的SDK
,对应的SDK
库文件就是放这个目录中(子目录Plugins/Android
和Plugins/iOS
)。还有你可能会用到一些第三方库,比如HoTween.dll
、Zxing.dll
、Ionic.Zip.Unity.dll
等,都是放在Plugins
中。
shader
一般是技术美术来写。Unity2018
推出了ShaderGraph
,我之前写了一篇关于ShaderGraph
的实战文章,大家有兴趣可以看看:https://blog.csdn.net/linxinfa/article/details/108049048
在编辑器环境下,直接使用这种方式加载资源。
比如加载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
Resources
目录中的资源,通过Resources.Load
同步加载。
比如加载Assets/Resources/Cube.prefab
。
//加载预设,注意不用带.prefab后缀
GameObject prefab = Resources.Load<GameObject>("Cube");
//实例化预设
GameObject go = Instantiate<GameObject>(prefab);
一般我们是将GameRes
目录中的资源打成AssetBundle
放在StreamingAssets
目录中,然后通过WWW
或UnityWebRequest
异步加载,或者通过AssetBundle.LoadFromFile
同步加载。
首先,对资源设置AssetBunle
名称,建议以所在目录为名称,比如下图中的Cube
和Sphere
两个预设,都设置成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");
}
}
接着,通过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
目录中看到了
接下来是游戏运行时加载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
中找。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。