Created
March 19, 2020 21:03
-
-
Save mandarinx/df5e9bd6e5a8a3badd81dd92bd83d938 to your computer and use it in GitHub Desktop.
Explosion system
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//#define LOG | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Text; | |
using AptGames; | |
using TerrorSquid.BulletSystem; | |
using UnityEngine; | |
using TerrorSquid.Entities; | |
using UnityEngine.AddressableAssets; | |
using UnityEngine.ResourceManagement.AsyncOperations; | |
using UnityEngine.SceneManagement; | |
using Debug = UnityEngine.Debug; | |
namespace TerrorSquid.ExplosionSystem { | |
public static class Explosions { | |
private static readonly Dictionary<int, int> current = new Dictionary<int, int>(); | |
private static readonly Dictionary<int, int> lengths = new Dictionary<int, int>(); | |
private static readonly Dictionary<int, int> offsetMap = new Dictionary<int, int>(); | |
private static float[] radius; | |
private static Explosion[] instances; | |
private static bool[] active; | |
private static Transform[] transforms; | |
private static int[] explosionHashes; | |
private static int[] offsets; | |
private static int[] counts; | |
private static int totalBullets; | |
public static void Init(BulletPatternSequence sequence) { | |
totalBullets = sequence.GetTotalBullets(); | |
instances = new Explosion[totalBullets]; | |
transforms = new Transform[totalBullets]; | |
radius = new float[totalBullets]; | |
active = new bool[totalBullets]; | |
} | |
public static int GetLength(int hash) { | |
return lengths[hash]; | |
} | |
#if DEV | |
public static string GetStatus() { | |
StringBuilder sb = new StringBuilder(); | |
for (int i = 0; i < explosionHashes.Length; ++i) { | |
int explHash = explosionHashes[i]; | |
int cur = current[explHash]; | |
sb.AppendLine($"ID {explHash} cur: {cur}"); | |
} | |
return sb.ToString(); | |
} | |
#endif | |
public static void Spawn(int explosionHash, Vector3 pos, Quaternion rotLocalSphere) { | |
int typeIndex = Array.IndexOf(explosionHashes, explosionHash); | |
#if DEV | |
if (typeIndex < 0) { | |
throw new Exception($"Cannot find explosion hash {explosionHash} in list of hashes"); | |
} | |
#endif | |
#if DEV | |
if (typeIndex >= offsets.Length) { | |
throw new Exception($"Type index {typeIndex} for hash {explosionHash} is greater than the length of offsets array"); | |
} | |
if (!current.ContainsKey(explosionHash)) { | |
throw new Exception($"Current dictionary does not contain a key for hash {explosionHash}"); | |
} | |
#endif | |
int offset = offsets[typeIndex]; | |
int cur = current[explosionHash]; | |
int instanceIndex = offset + cur; | |
#if DEV | |
if (instanceIndex >= instances.Length || instanceIndex < 0) { | |
throw new Exception($"Instance index {instanceIndex} is out of range of instances array"); | |
} | |
#endif | |
transforms[instanceIndex].SetPositionAndRotation(pos, rotLocalSphere); | |
instances[instanceIndex].Play(); | |
active[instanceIndex] = true; | |
counts[typeIndex] = counts[typeIndex] + 1; | |
int len = lengths[explosionHash]; | |
for (int i = cur + 1; i < len; ++i) { | |
if (!active[offset + i]) { | |
current[explosionHash] = i; | |
break; | |
} | |
} | |
Log($"Spawn"+ | |
$", hash: {explosionHash}"+ | |
$", typeIndex: {typeIndex}"+ | |
$", offset: {offset}"+ | |
$", instanceIndex: {instanceIndex}"+ | |
$", current: {current[explosionHash]}"+ | |
$", count: {counts[typeIndex]}"); | |
} | |
public static void Pause() { | |
int len = explosionHashes.Length; | |
for (int h = 0; h < len; ++h) { | |
int offset = offsets[h]; | |
int count = counts[h]; | |
for (int i = offset; i < offset + count; ++i) { | |
instances[i].Pause(); | |
} | |
} | |
} | |
public static void Resume() { | |
int len = explosionHashes.Length; | |
for (int h = 0; h < len; ++h) { | |
int offset = offsets[h]; | |
int count = counts[h]; | |
for (int i = offset; i < offset + count; ++i) { | |
instances[i].Resume(); | |
} | |
} | |
} | |
private static void Despawn(int instanceIndex) { | |
int seqIndex = GetSequenceIndex(instanceIndex); | |
instances[instanceIndex].Stop(); | |
transforms[instanceIndex].localPosition = Vector3.zero; | |
active[instanceIndex] = false; | |
int explosionHash = explosionHashes[seqIndex]; | |
if (instanceIndex < current[explosionHash]) { | |
current[explosionHash] = instanceIndex; | |
} | |
counts[seqIndex] = counts[seqIndex] - 1; | |
Log($"Despawn"+ | |
$", instanceIndex: {instanceIndex}"+ | |
$", current: {current[explosionHash]}"+ | |
$", count: {counts[seqIndex]}"+ | |
$", active: {active[instanceIndex]}"); | |
} | |
public static void Update(float dt) { | |
int len = explosionHashes.Length; | |
for (int h = 0; h < len; ++h) { | |
int hash = explosionHashes[h]; | |
int offset = offsets[h]; | |
int count = counts[h]; | |
int cur = count; | |
for (int it = count; it > 0; --it) { | |
int i = it - 1; | |
int n = offset + i; | |
if (!instances[n].IsAlive()) { | |
Despawn(n); | |
cur = i; | |
} | |
} | |
current[hash] = cur; | |
} | |
} | |
private static int GetSequenceIndex(int instanceIndex) { | |
int index = 0; | |
for (int i = 0; i < offsets.Length - 1; ++i) { | |
if (offsets[i + 1] > instanceIndex) { | |
return index; | |
} | |
++index; | |
} | |
return index; | |
} | |
public static void DespawnAll() { | |
for (int i = 0; i < totalBullets; ++i) { | |
instances[i].Stop(); | |
active[i] = false; | |
} | |
int hashes = explosionHashes.Length; | |
for (int h = 0; h < hashes; ++h) { | |
int hash = explosionHashes[h]; | |
current[hash] = 0; | |
} | |
} | |
public static float GetRadiusByNameHash(int nameHash) { | |
return radius[Array.IndexOf(explosionHashes, nameHash)]; | |
} | |
public static IEnumerator Load(LoadState loadState, BulletPatternSequence sequence) { | |
loadState.explosionsLoaded = 0; | |
loadState.explosionsToLoad = sequence.GetTotalBullets(); | |
// Load assets by label | |
AsyncOperationHandle<IList<GameObject>> handle = Addressables.LoadAssetsAsync<GameObject>("explosion", null); | |
yield return handle; | |
Dictionary<int, GameObject> prefabs = new Dictionary<int, GameObject>(); | |
for (int i = 0; i < handle.Result.Count; ++i) { | |
prefabs.Add(HashUtils.Simple(handle.Result[i].name), handle.Result[i]); | |
} | |
int seqLen = sequence.Count; | |
for (int i = 0; i < seqLen; ++i) { | |
PatternConfig cfg = sequence.Get(i); | |
int explosionHash = cfg.ExplosionHash; | |
current[explosionHash] = 0; | |
if (lengths.ContainsKey(explosionHash)) { | |
lengths[explosionHash] += cfg.MaxNum; | |
} else { | |
lengths[explosionHash] = cfg.MaxNum; | |
} | |
} | |
List<int> uniqueHashes = new List<int>(); | |
for (int i = 0; i < seqLen; ++i) { | |
if (!uniqueHashes.Contains(sequence.Get(i).ExplosionHash)) { | |
uniqueHashes.Add(sequence.Get(i).ExplosionHash); | |
} | |
} | |
explosionHashes = uniqueHashes.ToArray(); | |
offsets = new int[explosionHashes.Length]; | |
counts = new int[explosionHashes.Length]; | |
{ | |
int offset = 0; | |
for (int i = 0; i < explosionHashes.Length; ++i) { | |
offsets[i] = offset; | |
offsetMap.Add(explosionHashes[i], offset); | |
offset += lengths[explosionHashes[i]]; | |
} | |
} | |
Scene sceneExplosions = SceneManager.CreateScene("Explosions"); | |
for (int i = 0; i < explosionHashes.Length; ++i) { | |
int explosionHash = explosionHashes[i]; | |
int length = lengths[explosionHash]; | |
int offset = offsets[i]; | |
GameObject prefab = prefabs[explosionHash]; | |
for (int e = 0; e < length; ++e) { | |
int n = offset + e; | |
instances[n] = GameObject.Instantiate(prefab).GetComponent<Explosion>(); | |
instances[n].gameObject.name = $"{prefab.name}_{e:0000}"; | |
transforms[n] = instances[n].transform; | |
radius[n] = instances[n].Radius; | |
SceneManager.MoveGameObjectToScene(instances[n].gameObject, sceneExplosions); | |
++loadState.explosionsLoaded; | |
if (n % CONST.INSTANTIATES_PER_FRAME == 0) { | |
yield return null; | |
} | |
} | |
} | |
} | |
[Conditional("LOG")] | |
private static void Log(object msg) { | |
Debug.Log(msg); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment