【发布时间】:2022-01-01 04:41:35
【问题描述】:
我一直在使用 Unity 游戏引擎为 android 设备开发一款益智游戏,但我一直面临从内部存储加载图像的问题。游戏有400-500个关卡。在运行时根据需要下载,并存储在内部存储中。加载这些图像时会出现问题。从内部存储加载图像非常昂贵。下面是负责下载或加载图片的函数,
public IEnumerator DownloadOrLoadImage(string link, string dirName, int index = -1)
{
if (!loadFromResources)
{
//Extract Link
int startPos = link.LastIndexOf("https://drive.google.com/file/d/") + "https://drive.google.com/file/d/".Length;
int length = link.IndexOf("/view?usp=sharing") - startPos;
if (length >= 1)
{
string ID = link.Substring(startPos, length);
link = "https://drive.google.com/uc?export=download&id=" + ID;
if (File.Exists(Application.persistentDataPath + "/.cache/" + ID))
{
if (index != -1 && index == LevelMenuLoader.instance.totalJsonCount)
{
LevelMenuLoader.instance.AfterMenuDownloadSequence();
}
print("Loading from the device");
UnityWebRequest request = UnityWebRequestTexture.GetTexture("file://" + Application.persistentDataPath + "/.cache/" + ID);
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
{
Debug.Log(request.error);
}
else
{
byte[] bytes = ((DownloadHandlerTexture)request.downloadHandler).data;
if (bytes.Length > 1)
this.GetComponent<RawImage>().texture = ((DownloadHandlerTexture)request.downloadHandler).texture;
}
request.downloadHandler.Dispose();
request.Dispose();
isImageDownloaded = true;
}
else
{
LevelMenuLoader.instance.AfterMenuDownloadSequence();
print("Downloading from the web");
using (UnityWebRequest request = UnityWebRequestTexture.GetTexture(link))
{
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
Debug.Log(request.error);
else
{
this.GetComponent<RawImage>().texture = ((DownloadHandlerTexture)request.downloadHandler).texture;
byte[] bytes = ((DownloadHandlerTexture)request.downloadHandler).data;
if (bytes.Length > 1)
{
File.WriteAllBytes(Application.persistentDataPath + "/.cache/" + ID, bytes);
isImageDownloaded = true;
}
request.downloadHandler.Dispose();
request.Dispose();
}
}
}
}
}
else
{
// Debug.Log("Loaded from resources");
this.GetComponent<RawImage>().texture = Resources.Load<Texture>("Levels/" + dirName + "/" + this.GetComponent<LevelInformation>().m_LevelID);
}
很抱歉它这么长,但它只是在检查文件是否存在,从存储中加载图像或下载它。我发现这是迄今为止最有效且延迟最少的方法。加载 300 多张图片时,非常令人头疼,加载图像需要 3-4 秒,并且在某些设备中,由于某些设备的内存使用限制,它根本不会加载。如果有人可以帮助或指导我以一种非常无缝且加载图像更快的方式优化代码,那将非常有帮助。
PS:我已经为滚动视图尝试了对象池,所以我只加载需要的图像并在它们在屏幕上不可见时处理它们。但这是不切实际的,因为加载图像会产生一点延迟,而且速度不如需要的快。任何建议都会很棒。
如果我违反了任何准则或我的格式不好,我很抱歉。请告诉我,以便我更正。
谢谢。
【问题讨论】:
-
您必须牺牲加载时间或内存。否则,您是否尝试为查看大量图像的屏幕创建较小的缩略图(当下载到设备或从服务器时,或者动态创建,尽管我怀疑这不可行,因为您已经有加载时间问题)?
-
嗨,@LukeVo 感谢您的回复。我不介意加载时间,但在内存中加载 400 多张图像会产生很多问题(内存不是很多),但有些设备会出现内存使用量突然激增的限制,这会阻止游戏加载图像。它在三星设备和 IOS 中受到高度关注。因此,游戏不会超过加载。缩略图在 512x512 中非常小,每个大约 100kb。这是我猜想的最小的缩略图。这些图像加载问题仅适用于滚动视图中需要这 400 多张图像的菜单。
-
我以前是开发游戏的,现在不知道是不是不一样了,但是100kB的图片文件在内存中的占用空间不一样。在内存中它总是位图(即每个像素 3 或 4 个字节)。 512x512 相当大!我记得当时(10 年前)我们只能加载大约 2048x2048 的纹理并将所有内容压缩到该限制内。
-
我明白了。有什么解决方法吗?因为我想低于 512x512 会导致质量很差。我们对图像进行了最大程度的优化,以保持较小尺寸的质量。
-
为什么需要加载全部 300 张图片?用户无法一次查看所有内容。假设我假设您有一个菜单屏幕,因此用户可以选择一个级别,以及一个实际上需要大好图像才能玩的屏幕。菜单屏幕,例如,您加载 30 个 50x50 的缩略图,这将非常快并且不会占用大量内存。然后到播放屏幕,你实际上加载了 512x512 的文件。
标签: c# android performance unity3d