当前位置:网站首页>A method of sequentially loading Unity Resources
A method of sequentially loading Unity Resources
2022-07-06 18:20:00 【ttod】
unity Provides the basis for UnityWebRequest Class to load some columns of resources , But if you simply load the content to be loaded at the same time, it will cause instant jamming , At the same time, the order of resource loading cannot be controlled . Because sometimes we need to control the loading order of resources , So I made a script to solve this problem . Not that this script must be good , Because there may be many schemes much better than this , perhaps unity It provides better functions , But I don't know how to use it . Anyway? , Online code bar .
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
public class LoadFromStreamingAssets : MonoBehaviour
{
class ObjHolder
{
public readonly string fullPath;
public readonly object obj;
public ObjHolder(string fullPath, object obj)
{
this.fullPath = fullPath;
this.obj = obj;
}
}
public class LoadInfo
{
public readonly string fullPath;
public LoadInfo(string relativePath)
{
fullPath = Application.streamingAssetsPath + "/" + relativePath;
}
}
public class ObjLoadInfo : LoadInfo
{
public readonly string objName;
public ObjLoadInfo(string relativePath, string objName) : base(relativePath)
{
this.objName = objName;
}
}
public class GameObjectLoadInfo : ObjLoadInfo
{
public UnityAction<GameObject> onLoaded;
public GameObjectLoadInfo(string relativePath, string objName, UnityAction<GameObject> onLoaded) : base(relativePath, objName)
{
this.onLoaded = onLoaded;
}
}
public class CubemapLoadInfo : ObjLoadInfo
{
public UnityAction<Cubemap> onLoaded;
public CubemapLoadInfo(string relativePath, string objName, UnityAction<Cubemap> onLoaded) : base(relativePath, objName)
{
this.onLoaded = onLoaded;
}
}
public class TextLoadInfo : LoadInfo
{
public UnityAction<string> onLoaded;
public TextLoadInfo(string relativePath, UnityAction<string> onLoaded) : base(relativePath)
{
this.onLoaded = onLoaded;
}
}
public class Texture2DLoadInfo : LoadInfo
{
public UnityAction<Texture2D> onLoaded;
public Texture2DLoadInfo(string relativePath, UnityAction<Texture2D> onLoaded) : base(relativePath)
{
this.onLoaded = onLoaded;
}
}
public class AudioLoadInfo : LoadInfo
{
public UnityAction<AudioClip> onLoaded;
public readonly AudioType audioType;
public AudioLoadInfo(string relativePath, AudioType audioType, UnityAction<AudioClip> onLoaded) : base(relativePath)
{
this.audioType = audioType;
this.onLoaded = onLoaded;
}
}
static public LoadFromStreamingAssets instance;
void Awake()
{
instance = this;
}
Queue<LoadInfo> loadInfoQueue = new Queue<LoadInfo>();
public void AddLoadInfo(LoadInfo loadInfo)
{
loadInfoQueue.Enqueue(loadInfo);
}
List<ObjHolder> objHolderList = new List<ObjHolder>();
void AddObjHolder(ObjHolder objHolder)
{
objHolderList.Add(objHolder);
}
ObjHolder GetObjHolder(string fullPath)
{
foreach (ObjHolder h in objHolderList)
{
if (h.fullPath == fullPath) return h;
}
return null;
}
void Start()
{
StartWaitLoad();
}
void StartWaitLoad()
{
StartCoroutine(WaitLoad());
}
IEnumerator WaitLoad()
{
yield return new WaitUntil(() => loadInfoQueue.Count > 0);
LoadByQueue();
}
void LoadByQueue()
{
LoadInfo info = loadInfoQueue.Dequeue();
if (info == null)
{
ContinueLoad();
}
else
{
ObjHolder objHolder = GetObjHolder(info.fullPath);
if (info is GameObjectLoadInfo)
{
GameObjectLoadInfo loadInfo = info as GameObjectLoadInfo;
if (loadInfo != null)
{
if (objHolder != null)
{
GameObject o = objHolder.obj as GameObject;
loadInfo.onLoaded(o);
ContinueLoad();
}
else
{
loadInfo.onLoaded += (GameObject o) => { if (o) { AddObjHolder(new ObjHolder(loadInfo.fullPath, o)); } };
loadInfo.onLoaded += delegate { ContinueLoad(); };
LoadGameObject(loadInfo);
}
}
else
{
ContinueLoad();
}
}
else if(info is CubemapLoadInfo)
{
CubemapLoadInfo loadInfo = info as CubemapLoadInfo;
if (loadInfo != null)
{
if (objHolder != null)
{
Cubemap c = objHolder.obj as Cubemap;
loadInfo.onLoaded(c);
ContinueLoad();
}
else
{
loadInfo.onLoaded += (Cubemap c) => { if (c) { AddObjHolder(new ObjHolder(loadInfo.fullPath, c)); } };
loadInfo.onLoaded += delegate { ContinueLoad(); };
LoadCubemap(loadInfo);
}
}
else
{
ContinueLoad();
}
}
else if (info is TextLoadInfo)
{
TextLoadInfo loadInfo = info as TextLoadInfo;
if (loadInfo != null)
{
if (objHolder != null)
{
string s = objHolder.obj as string;
loadInfo.onLoaded(s);
ContinueLoad();
}
else
{
loadInfo.onLoaded += (string s) => { if (s!=null) { AddObjHolder(new ObjHolder(loadInfo.fullPath, s)); } };
loadInfo.onLoaded += delegate { ContinueLoad(); };
LoadText(loadInfo);
}
}
else
{
ContinueLoad();
}
}
else if (info is Texture2DLoadInfo)
{
Texture2DLoadInfo loadInfo = info as Texture2DLoadInfo;
if (loadInfo != null)
{
if (objHolder != null)
{
Texture2D t = objHolder.obj as Texture2D;
loadInfo.onLoaded(t);
ContinueLoad();
}
else
{
loadInfo.onLoaded += (Texture2D t) => { if (t != null) { AddObjHolder(new ObjHolder(loadInfo.fullPath, t)); } };
loadInfo.onLoaded += delegate { ContinueLoad(); };
LoadTexture2D(loadInfo);
}
}
else
{
ContinueLoad();
}
}
else if (info is AudioLoadInfo)
{
AudioLoadInfo loadInfo = info as AudioLoadInfo;
if (loadInfo != null)
{
if (objHolder != null)
{
AudioClip a = objHolder.obj as AudioClip;
loadInfo.onLoaded(a);
ContinueLoad();
}
else
{
loadInfo.onLoaded += (AudioClip a) => { if (a != null) { AddObjHolder(new ObjHolder(loadInfo.fullPath, a)); } };
loadInfo.onLoaded += delegate { ContinueLoad(); };
LoadAudioClip(loadInfo);
}
}
else
{
ContinueLoad();
}
}
}
}
void ContinueLoad()
{
if (loadInfoQueue.Count == 0)
{
StartWaitLoad();
}
else
{
LoadByQueue();
}
}
void LoadGameObject(GameObjectLoadInfo LoadInfo)
{
StartCoroutine(GetAssetBundle(LoadInfo.fullPath, (AssetBundle ab) => { AssetbundleToGameObject(ab, LoadInfo.objName, LoadInfo.onLoaded); }));
}
void AssetbundleToGameObject(AssetBundle ab, string objName, UnityAction<GameObject> onLoaded)
{
if (ab)
{
GameObject obj = ab.LoadAsset<GameObject>(objName);
onLoaded?.Invoke(obj);
}
else
{
onLoaded?.Invoke(null);
}
}
void LoadCubemap(CubemapLoadInfo loadInfo)
{
StartCoroutine(GetAssetBundle(loadInfo.fullPath, (AssetBundle ab) => { AssetbundleToCubemap(ab, loadInfo.objName, loadInfo.onLoaded); }));
}
void AssetbundleToCubemap(AssetBundle ab, string objName, UnityAction<Cubemap> onLoaded)
{
if (ab)
{
Cubemap cubemap = ab.LoadAsset<Cubemap>(objName);
onLoaded?.Invoke(cubemap);
}
else
{
onLoaded?.Invoke(null);
}
}
IEnumerator GetAssetBundle(string path, UnityAction<AssetBundle> onGetAssetBundle)
{
using (UnityWebRequest webRequest = UnityWebRequestAssetBundle.GetAssetBundle(path))
{
yield return webRequest.SendWebRequest();
if (webRequest.result == UnityWebRequest.Result.Success)
{
AssetBundle ab = (webRequest.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
onGetAssetBundle?.Invoke(ab);
ab.Unload(false);
}
else
{
Debug.Log("error = " + webRequest.error + "\n Load Path = " + path);
onGetAssetBundle?.Invoke(null);
}
}
}
void LoadText(TextLoadInfo loadInfo)
{
StartCoroutine(GetText(loadInfo.fullPath, loadInfo.onLoaded));
}
IEnumerator GetText(string path, UnityAction<string> onGetJson)
{
using (UnityWebRequest webRequest = UnityWebRequest.Get(path))
{
yield return webRequest.SendWebRequest();
if (webRequest.result == UnityWebRequest.Result.Success)
{
string json = webRequest.downloadHandler.text;
onGetJson?.Invoke(json);
}
else
{
Debug.Log("error = " + webRequest.error + "\n Load Path = " + path);
onGetJson?.Invoke(null);
}
}
}
void LoadTexture2D(Texture2DLoadInfo loadInfo)
{
StartCoroutine(GetTexture2D(loadInfo.fullPath, loadInfo.onLoaded));
}
IEnumerator GetTexture2D(string path, UnityAction<Texture2D> onGetTexture2D)
{
using (UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture(path))
{
yield return webRequest.SendWebRequest();
if (webRequest.result == UnityWebRequest.Result.Success)
{
Texture2D tex2d = DownloadHandlerTexture.GetContent(webRequest);
onGetTexture2D?.Invoke(tex2d);
}
else
{
Debug.Log("error = " + webRequest.error + "\n Load Path = " + path);
onGetTexture2D?.Invoke(null);
}
}
}
void LoadAudioClip(AudioLoadInfo loadInfo)
{
StartCoroutine(GetAudio(loadInfo.fullPath, loadInfo.audioType, loadInfo.onLoaded));
}
IEnumerator GetAudio(string path, AudioType type, UnityAction<AudioClip> onGetAudio)
{
using (UnityWebRequest webRequest = UnityWebRequestMultimedia.GetAudioClip(path, type))
{
yield return webRequest.SendWebRequest();
if (webRequest.result == UnityWebRequest.Result.Success)
{
AudioClip clip = DownloadHandlerAudioClip.GetContent(webRequest);
onGetAudio?.Invoke(clip);
}
else
{
Debug.Log("error = " + webRequest.error + "\n Load Path = " + path);
onGetAudio?.Invoke(null);
}
}
}
}
These codes mean that a resource is loaded ( Or loading failed ) Then the next resource can be loaded , Multiple resources are not allowed to load at the same time . At the same time, the references of the loaded resources are saved , If the resources that need to be loaded have actually been loaded , Just get it directly from these references , No need to download again . As for which resources are loaded first , Which resources are loaded later , It is mainly determined by the order in which the resource loading information is added to the queue . The following script uses yield return null To determine how many frames to delay before adding the loading information to the queue , This seems not a very good way , But at least for now it works , There should be a better way , Let's do that first. .
Here is the sample code :
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
public class LoadGameObject : MonoBehaviour
{
[SerializeField]
string loadPath;
[SerializeField]
string objName;
[SerializeField]
bool replaceLitShader = true;
[SerializeField]
bool replaceObstacle = true;
[SerializeField]
bool replaceCollider = true;
[SerializeField]
string layerName = "CamCol";
[SerializeField]
bool isTree = false;
[SerializeField]
int delayFrame = 0;
IEnumerator Start()
{
for (int i = 0; i < delayFrame; i++)
{
yield return null;
}
string relativePath = loadPath + "/" + objName.ToLower() + ".ab";
LoadFromStreamingAssets.GameObjectLoadInfo info = new LoadFromStreamingAssets.GameObjectLoadInfo(relativePath, objName, InstantiateObject);
LoadFromStreamingAssets.instance.AddLoadInfo(info);
}
GameObject _obj = null;
public GameObject loadedObj { get { return _obj; } }
UnityAction<GameObject> onLoadedObj;
public void AddActLoadedObj(UnityAction<GameObject> act) { onLoadedObj -= act; onLoadedObj += act; }
public void RemoveActLoadedObj(UnityAction<GameObject> act) { onLoadedObj -= act; }
void InstantiateObject(GameObject prefab)
{
if (prefab)
{
GameObject obj = Instantiate(prefab);
if (obj)
{
obj.transform.SetParent(transform);
obj.transform.localPosition = Vector3.zero;
obj.transform.localRotation = Quaternion.identity;
obj.transform.localScale = Vector3.one;
MeshRenderer[] renders = obj.GetComponentsInChildren<MeshRenderer>();
if (replaceLitShader)
{
foreach (MeshRenderer render in renders)
{
foreach (Material mat in render.materials)
{
mat.shader = isTree ? ShaderHolder.instance.SpeedTree8 : ShaderHolder.instance.URPLit;
}
}
}
if (replaceObstacle)
{
NavMeshObstacle obstacle = obj.GetComponentInChildren<NavMeshObstacle>();
if (obstacle)
{
if (replaceCollider)
{
BoxCollider col = obstacle.GetComponent<BoxCollider>();
if (!col)
{
col = obj.AddComponent<BoxCollider>();
col.size = obstacle.size;
col.center = obstacle.center;
}
}
}
}
obj.layer = LayerMask.NameToLayer(layerName);
onLoadedObj?.Invoke(obj);
_obj = obj;
}
}
}
}
The above is some interesting content in recent work .
边栏推荐
猜你喜欢
FMT开源自驾仪 | FMT中间件:一种高实时的分布式日志模块Mlog
Rb157-asemi rectifier bridge RB157
Today in history: the mother of Google was born; Two Turing Award pioneers born on the same day
传输层 拥塞控制-慢开始和拥塞避免 快重传 快恢复
Jerry's updated equipment resource document [chapter]
std::true_ Type and std:: false_ type
第三季百度网盘AI大赛盛夏来袭,寻找热爱AI的你!
Virtual machine VirtualBox and vagrant installation
F200 - UAV equipped with domestic open source flight control system based on Model Design
Excellent open source fonts for programmers
随机推荐
【LeetCode第 300 场周赛】
【.NET CORE】 请求长度过长报错解决方案
Excellent open source fonts for programmers
第三季百度网盘AI大赛盛夏来袭,寻找热爱AI的你!
STM32+ESP8266+MQTT协议连接OneNet物联网平台
Introduction to the usage of model view delegate principal-agent mechanism in QT
测试123
Implementation of queue
Will openeuler last long
小程序在产业互联网中的作用
高精度运算
Interview shock 62: what are the precautions for group by?
图片缩放中心
Windows connects redis installed on Linux
Jerry's access to additional information on the dial [article]
文档编辑之markdown语法(typora)
Cobra 快速入门 - 专为命令行程序而生
Redis的五种数据结构
【Android】Kotlin代码编写规范化文档
Jerry is the custom background specified by the currently used dial enable [chapter]