在Unity中从资源包中加载资源



我目前正在维护一个旧项目,如果可能的话,我非常希望保留旧代码并避免重构旧代码。为了上传到google play store,我使用了play asset delivery PAD系统,这需要asset bundle系统。

我能够按照教程的协同程序以异步方式成功加载资源包。

我的问题是;是否可以在不改变原始访问方式(如

)的情况下访问捆绑资产?
UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Prefabs/Game/Tiles/Tile.prefab", typeof(Tile)) as Tile;

而不是实现下面的代码?

var assets = AssetDatabase.FindAssets("t:Sprite", 
new[] {"Assets/Images"});
foreach (var guid in assets) 
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
Sprite loadedSprite = null;
if (imageDictionary.TryGetValue(assetPath, out loadedSprite) 
== false)
{
loadedSprite = AssetDatabase.LoadAssetAtPath<Sprite>(
assetPath);
if (loadedSprite != null)
{
imageDictionary.Add(assetPath, loadedSprite);
AddImageToList(assetPath, loadedSprite);       
}
}
}

我目前使用2个资源包,包括纹理和脊柱动画文件夹。我已经创建了2个资源包,分别是纹理文件夹(110 MB)和脊柱动画包(23 MB)和基础资源。当我创建aab文件时,文件大小增加到370mb。(我知道我需要拆分我的包,以满足游戏商店150mb的基本资产要求,但这是另一个问题。)

而且,我有根据的猜测是,unity不仅是添加资产包,而且还以老式的方式添加资产,这是一个可能与这个问题相关的问题。

我也面临着同样的问题。最初构建的AAB文件超过150MB,无法上传到商店。但是我找到了上传的方法。

订单

  1. 将构建场景放到"File - BuildSetting - scene in build"中。

  2. 检查"构建应用程序包";in "File - BuildSetting"

  3. 关闭BuildSetting,点击"Google - Build Android App bundle";构建。(在这个过程中,我没有创建一个AssetBundle。我使用原来的程序)

  4. 忽略构建过程中出现的大尺寸告警

  5. 当构建完成时,大小将大于150MB。不要担心构建文件的大小,把它上传到Google控制台。

Google - Build Android App Bundle"用它建立的文件上升。我希望这个问题得到解决。

@Alp,谷歌的PAD教程是相当有限的,它只是猜测你试图访问纹理,这可能并不总是如此。实际上你可以直接访问bundle,并将它们加载到内存中,如果你已经将你的prefab打包为一个assetBundle,当你以这种方式加载你的assetBundle时,你可以稍后将其转换为一个GameObject,然后使用prefab作为一个GameObject来实例化它或做任何你需要的事情。

只有一种官方的方式加载资源包,如果你把它们打包在安装时,

public static IEnumerator LoadAssetBundleFromMemoryAsync(string packName, string assetName, Action<AssetBundle> callback)
{
var packRequest = PlayAssetDelivery.RetrieveAssetPackAsync(packName);
while (!packRequest.IsDone) 
{
yield return null;
}
AssetLocation location = packRequest.GetAssetLocation(assetName);
long size = (long)location.Size;
long offset = (long)location.Offset;

using (Stream stream = File.OpenRead(location.Path)) 
{
byte[] bytes = new byte[size];
stream.Seek(offset, SeekOrigin.Begin);
stream.Read(bytes, 0, bytes.Length);
AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(bytes);
yield return request;
callback(request.assetBundle);
}
}

然后,我还想出了一种非官方的方式直接从文件加载资源包。事实证明,我们为给定的assetBundle获得的位置将在与assetPack同名的split apk模块中。但是如果我们把split_pack.apk替换为base.apk,我们就可以直接从File中读取它,而不需要将bundle预加载到内存中。从内存加载会提前把它放到内存中,而使用LoadFromFile方式,你可以在需要的时候把bundle加载到内存中。像这样:

public static IEnumerator LoadAssetBundleFromFileAsync (string packName, string assetName, Action<AssetBundle> callback) 
{
var packRequest = PlayAssetDelivery.RetrieveAssetPackAsync(packName);
while (!packRequest.IsDone)
{
yield return null;
}
AssetLocation location = packRequest.GetAssetLocation(assetName);
string path = location.Path.Replace($"split_{packName}.apk", "base.apk");    
string basePath =  $"{path}!assets/assetpack/{assetName}";
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(basePath);
while (!request.isDone) 
{
yield return null;
}
callback(request.assetBundle);
}

你也可以只返回'assetPath'然后加载它。

如果您试图从快速跟踪或按需资产包中加载任何文件,那么您所需要的就是位置。加载路径,作为原始文件。

public static IEnumerator GetAssetLocationFromAssetPack (string packName, string assetName, Action<string> callback) 
{
PlayAssetPackRequest packRequest = PlayAssetDelivery.RetrieveAssetPackAsync(packName);
while (!packRequest.IsDone) 
{
yield return null;
}

AssetLocation location = packRequest.GetAssetLocation(assetName);
callback(location.Path);
}

我希望它能有所帮助,并且要小心,StreamingAssets中包含的任何文件夹或资产,如果也设置为在assetPack中,将被添加到double中,StreamingAssets中包含的一切都将在base.apk中(在AAB中),所以如果你有一些来自StreamingAssets的东西,实际上将从包中加载,请从Streaming中删除它,以避免AAB大于预期。