当前位置:网站首页>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 .
边栏推荐
- 阿里云国际版ECS云服务器无法登录宝塔面板控制台
- Release of the sample chapter of "uncover the secrets of asp.net core 6 framework" [200 pages /5 chapters]
- Four processes of program operation
- Automatic reservation of air tickets in C language
- MSF horizontal MSF port forwarding + routing table +socks5+proxychains
- MSF横向之MSF端口转发+路由表+SOCKS5+proxychains
- declval(指导函数返回值范例)
- node の SQLite
- Easy to use PDF to SVG program
- 2019阿里集群数据集使用总结
猜你喜欢
Introduction to the usage of model view delegate principal-agent mechanism in QT
【.NET CORE】 请求长度过长报错解决方案
Scratch epidemic isolation and nucleic acid detection Analog Electronics Society graphical programming scratch grade examination level 3 true questions and answers analysis June 2022
推荐好用的后台管理脚手架,人人开源
Compilation principle - top-down analysis and recursive descent analysis construction (notes)
Grafana 9.0 is officially released! It's the strongest!
關於這次通信故障,我想多說幾句…
[swoole series 2.1] run the swoole first
Recursive way
面向程序员的精品开源字体
随机推荐
echart简单组件封装
Jerry's watch reads the file through the file name [chapter]
d绑定函数
二分(整数二分、实数二分)
win10系统下插入U盘有声音提示却不显示盘符
[swoole series 2.1] run the swoole first
Reprint: defect detection technology of industrial components based on deep learning
2019 Alibaba cluster dataset Usage Summary
IP, subnet mask, gateway, default gateway
简单易用的PDF转SVG程序
Ms-tct: INRIA & SBU proposed a multi-scale time transformer for motion detection. The effect is SOTA! Open source! (CVPR2022)...
30 分钟看懂 PCA 主成分分析
小程序在产业互联网中的作用
Top command details
递归的方式
POJ 2208 已知边四面体六个长度,计算体积
2019阿里集群数据集使用总结
std::true_type和std::false_type
解读云原生技术
從交互模型中蒸餾知識!中科大&美團提出VIRT,兼具雙塔模型的效率和交互模型的性能,在文本匹配上實現性能和效率的平衡!...