Skip to content

Instantly share code, notes, and snippets.

@unity3dcollege
Created September 29, 2019 16:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save unity3dcollege/92c78818a033e4f52709a8f2ab6faf0f to your computer and use it in GitHub Desktop.
Save unity3dcollege/92c78818a033e4f52709a8f2ab6faf0f to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class ParticleSpawner : MonoBehaviour
{
[SerializeField] private List<AssetReference> _particleReferences;
private Dictionary<AssetReference, List<GameObject>> _spawnedParticleSystems = new Dictionary<AssetReference, List<GameObject>>();
private Dictionary<AssetReference, Queue<Vector3>> _queuedSpawnRequests = new Dictionary<AssetReference, Queue<Vector3>>();
private Dictionary<AssetReference, AsyncOperationHandle<GameObject>> _asyncOperationHandles =
new Dictionary<AssetReference, AsyncOperationHandle<GameObject>>();
public void Spawn(int index)
{
if (index < 0 || index >= _particleReferences.Count)
return;
AssetReference assetReference = _particleReferences[index];
if (assetReference.RuntimeKeyIsValid() == false)
{
Debug.Log("Invalid Key " + assetReference.RuntimeKey.ToString());
return;
}
if (_asyncOperationHandles.ContainsKey(assetReference))
{
if (_asyncOperationHandles[assetReference].IsDone)
SpawnParticleFromLoadedReference(assetReference, GetRandomPosition());
else
EnqueueSpawnForAfterInitialization(assetReference);
return;
}
LoadAndSpawn(assetReference);
}
private void LoadAndSpawn(AssetReference assetReference)
{
var op = Addressables.LoadAssetAsync<GameObject>(assetReference);
_asyncOperationHandles[assetReference] = op;
op.Completed += (operation) =>
{
SpawnParticleFromLoadedReference(assetReference, GetRandomPosition());
while (_queuedSpawnRequests?[assetReference].Any() == true)
{
var position = _queuedSpawnRequests[assetReference].Dequeue();
SpawnParticleFromLoadedReference(assetReference, position);
}
};
}
private void EnqueueSpawnForAfterInitialization(AssetReference assetReference)
{
if (_queuedSpawnRequests.ContainsKey(assetReference) == false)
_queuedSpawnRequests[assetReference] = new Queue<Vector3>();
_queuedSpawnRequests[assetReference].Enqueue(GetRandomPosition());
}
private void SpawnParticleFromLoadedReference(AssetReference assetReference, Vector3 position)
{
assetReference.InstantiateAsync(position, Quaternion.identity).Completed += (asyncOperationHandle) =>
{
if (_spawnedParticleSystems.ContainsKey(assetReference) == false)
{
_spawnedParticleSystems[assetReference] = new List<GameObject>();
}
_spawnedParticleSystems[assetReference].Add(asyncOperationHandle.Result);
var notify = asyncOperationHandle.Result.AddComponent<NotifyOnDestroy>();
notify.Destroyed += Remove;
notify.AssetReference = assetReference;
};
}
private Vector3 GetRandomPosition()
{
return new Vector3(UnityEngine.Random.Range(-5, 5), 0, UnityEngine.Random.Range(-5, 5));
}
private void Remove(AssetReference assetReference, NotifyOnDestroy obj)
{
Addressables.ReleaseInstance(obj.gameObject);
_spawnedParticleSystems[assetReference].Remove(obj.gameObject);
if (_spawnedParticleSystems[assetReference].Count == 0)
{
Debug.Log($"Removed all {assetReference.RuntimeKey.ToString()}");
if (_asyncOperationHandles[assetReference].IsValid())
Addressables.Release(_asyncOperationHandles[assetReference]);
_asyncOperationHandles.Remove(assetReference);
}
}
}
public class NotifyOnDestroy : MonoBehaviour
{
public event Action<AssetReference, NotifyOnDestroy> Destroyed;
public AssetReference AssetReference { get; set; }
public void OnDestroy()
{
Destroyed?.Invoke(AssetReference, this);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment