< Summary

Class:ParticleManager
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/Managers/ParticleManager.cs
Covered lines:32
Uncovered lines:153
Coverable lines:185
Total lines:269
Line coverage:17.2% (32 of 185)
Covered branches:0
Total branches:0
Covered methods:8
Total methods:28
Method coverage:28.5% (8 of 28)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ParticleManager()0%110100%
Awake()0%2.112070%
Start()0%3.473062.5%
Update()0%110100%
InitializeMissileTrailParticlePool()0%6200%
InitializeMissileExplosionParticlePool()0%6200%
RegisterSimulationEnded()0%2.262060%
RegisterNewInterceptor(...)0%2100%
RegisterNewThreat(...)0%110100%
RegisterAgentTerminated(...)0%6200%
RegisterInterceptorHit(...)0%6200%
RegisterInterceptorMiss(...)0%2100%
RegisterThreatHit(...)0%2100%
RegisterThreatMiss(...)0%2100%
CommandeerAgentTrailRenderer(...)0%20400%
SpawnHitMarker(...)0%2100%
ClearHitMarkers()0%6200%
PlayMissileExplosion(...)0%12300%
ReturnExplosionAfterDelay()0%12300%
ReturnMissileExplosionParticle(...)0%12300%
InstantiateMissileTrail(...)0%2100%
InstantiateMissileExplosion(...)0%2100%
InstantiateMissileTrailsOverTime()0%20400%
InstantiateMissileExplosionsOverTime()0%20400%
RequestMissileTrailParticle()0%12300%
ReturnMissileTrailParticle(...)0%12300%

File(s)

/github/workspace/Assets/Scripts/Managers/ParticleManager.cs

#LineLine coverage
 1using System.Collections;
 2using System.Collections.Generic;
 3using UnityEngine;
 4using System.Linq;
 5
 6public class ParticleManager : MonoBehaviour {
 27  public static ParticleManager Instance { get; private set; }
 8
 9  private Queue<GameObject> _missileTrailPool;
 10  [SerializeField]
 11  // Queues cannot be serialized, so if we want to see it in the inspector,
 12  // we need to serialize the count.
 13  private int _missileTrailPoolCount;
 14  [SerializeField]
 15  private Queue<GameObject> _missileExplosionPool;
 16  [SerializeField]
 17  private int _missileExplosionPoolCount;
 18
 19  [SerializeField]
 220  private List<TrailRenderer> _agentTrailRenderers = new List<TrailRenderer>();
 21
 22  [SerializeField, Tooltip("The material to use for commandeered interceptor trail renderers")]
 23  public Material interceptorTrailMatFaded;
 24  [SerializeField, Tooltip("The material to use for commandeered threat trail renderers")]
 25  public Material threatTrailMatFaded;
 26
 27  [SerializeField]
 228  private List<GameObject> _hitMarkerList = new List<GameObject>();
 29
 130  private void Awake() {
 231    if (Instance == null) {
 132      Instance = this;
 133      DontDestroyOnLoad(gameObject);
 134    } else {
 035      Destroy(gameObject);
 036    }
 137  }
 38
 139  private void Start() {
 140    _missileTrailPool = new Queue<GameObject>();
 141    _missileExplosionPool = new Queue<GameObject>();
 142    _hitMarkerList = new List<GameObject>();
 43
 144    if (SimManager.Instance.SimulatorConfig.EnableMissileTrailEffect) {
 045      InitializeMissileTrailParticlePool();
 046    }
 147    if (SimManager.Instance.SimulatorConfig.EnableExplosionEffect) {
 048      InitializeMissileExplosionParticlePool();
 049    }
 50
 51    // Subscribe to events.
 152    SimManager.Instance.OnNewInterceptor += RegisterNewInterceptor;
 153    SimManager.Instance.OnNewThreat += RegisterNewThreat;
 54
 155    SimManager.Instance.OnSimulationEnded += RegisterSimulationEnded;
 156  }
 57
 2858  private void Update() {
 2859    _missileTrailPoolCount = _missileTrailPool.Count;
 2860    _missileExplosionPoolCount = _missileExplosionPool.Count;
 2861  }
 62
 063  private void InitializeMissileTrailParticlePool() {
 64    // Grab from Resources/Prefabs/Effects
 065    GameObject missileTrailPrefab =
 66        Resources.Load<GameObject>("Prefabs/Effects/InterceptorSmokeEffect");
 67
 68    // Pre-instantiate 10 missile trail particles
 069    for (int i = 0; i < 10; ++i) {
 070      InstantiateMissileTrail(missileTrailPrefab);
 071    }
 72    // Instantiate over an interval
 073    StartCoroutine(InstantiateMissileTrailsOverTime(missileTrailPrefab, 200, 0.05f));
 074  }
 75
 076  private void InitializeMissileExplosionParticlePool() {
 077    GameObject missileExplosionPrefab =
 78        Resources.Load<GameObject>("Prefabs/Effects/InterceptExplosionEffect");
 79    // Pre-instantiate 10 missile trail particles
 080    for (int i = 0; i < 10; ++i) {
 081      InstantiateMissileExplosion(missileExplosionPrefab);
 082    }
 083    StartCoroutine(InstantiateMissileExplosionsOverTime(missileExplosionPrefab, 200, 0.05f));
 084  }
 85
 986  private void RegisterSimulationEnded() {
 2787    foreach (var trailRenderer in _agentTrailRenderers) {
 088      Destroy(trailRenderer.gameObject);
 089    }
 990    _agentTrailRenderers.Clear();
 991  }
 92
 093  private void RegisterNewInterceptor(Interceptor interceptor) {
 094    interceptor.OnInterceptHit += RegisterInterceptorHit;
 095    interceptor.OnInterceptMiss += RegisterInterceptorMiss;
 096    interceptor.OnTerminated += RegisterAgentTerminated;
 097  }
 98
 75599  private void RegisterNewThreat(Threat threat) {
 755100    threat.OnThreatHit += RegisterThreatHit;
 755101    threat.OnThreatMiss += RegisterThreatMiss;
 755102    threat.OnTerminated += RegisterAgentTerminated;
 755103  }
 104
 0105  private void RegisterAgentTerminated(Agent agent) {
 0106    if (SimManager.Instance.SimulatorConfig.PersistentFlightTrails) {
 0107      CommandeerAgentTrailRenderer(agent);
 0108    }
 0109  }
 110
 0111  private void RegisterInterceptorHit(Interceptor interceptor, Threat threat) {
 0112    if (SimManager.Instance.SimulatorConfig.EnableExplosionEffect) {
 0113      PlayMissileExplosion(interceptor.transform.position);
 0114    }
 0115    GameObject hitMarkerObject = SpawnHitMarker(interceptor.transform.position);
 0116    hitMarkerObject.GetComponent<UIEventMarker>().SetEventHit();
 0117    _hitMarkerList.Add(hitMarkerObject);
 0118  }
 119
 0120  private void RegisterInterceptorMiss(Interceptor interceptor, Threat threat) {
 121    // It does not make sense to commandeer the TrailRenderer for a miss.
 122    // As the interceptor remains in flight
 0123    GameObject hitMarkerObject = SpawnHitMarker(interceptor.transform.position);
 0124    hitMarkerObject.GetComponent<UIEventMarker>().SetEventMiss();
 0125    _hitMarkerList.Add(hitMarkerObject);
 0126  }
 127
 0128  private void RegisterThreatHit(Threat threat) {}
 129
 0130  private void RegisterThreatMiss(Threat threat) {}
 131
 0132  private void CommandeerAgentTrailRenderer(Agent agent) {
 133    // Take the TrailRenderer component off of the agent, onto us, and store it
 134    // (so we can destroy it later on simulation end)
 0135    TrailRenderer trailRenderer = agent.GetComponentInChildren<TrailRenderer>();
 0136    if (trailRenderer != null) {
 0137      trailRenderer.transform.parent = transform;
 0138      _agentTrailRenderers.Add(trailRenderer);
 0139      trailRenderer.material = (agent is Threat) ? threatTrailMatFaded : interceptorTrailMatFaded;
 0140    } else {
 0141      Debug.LogWarning("Agent has no TrailRenderer component");
 0142    }
 0143  }
 144
 0145  private GameObject SpawnHitMarker(Vector3 position) {
 0146    GameObject hitMarker = Instantiate(Resources.Load<GameObject>("Prefabs/HitMarkerPrefab"),
 147                                       position, Quaternion.identity);
 0148    _hitMarkerList.Add(hitMarker);
 0149    return hitMarker;
 0150  }
 151
 0152  public void ClearHitMarkers() {
 0153    foreach (var hitMarker in _hitMarkerList) {
 0154      Destroy(hitMarker);
 0155    }
 0156    _hitMarkerList.Clear();
 0157  }
 158
 159  /// Returns a missile explosion particle prefab from the pool and plays it at the specified
 160  /// location. If the pool is empty, it returns null.
 0161  public GameObject PlayMissileExplosion(Vector3 position) {
 0162    if (_missileExplosionPool.Count > 0) {
 0163      GameObject explosion = _missileExplosionPool.Dequeue();
 0164      explosion.transform.position = position;
 165
 0166      ParticleSystem particleSystem = explosion.GetComponent<ParticleSystem>();
 0167      if (particleSystem != null) {
 0168        particleSystem.Clear();
 0169        particleSystem.Play();
 0170        StartCoroutine(ReturnExplosionAfterDelay(explosion, particleSystem.main.duration));
 0171      } else {
 0172        Debug.LogError("Missile explosion particle has no ParticleSystem component");
 0173        _missileExplosionPool.Enqueue(explosion);
 0174        return null;
 175      }
 176
 0177      return explosion;
 178    }
 0179    return null;
 0180  }
 181
 0182  private IEnumerator ReturnExplosionAfterDelay(GameObject explosion, float delay) {
 0183    yield return new WaitForSeconds(delay);
 0184    ReturnMissileExplosionParticle(explosion);
 0185  }
 186
 0187  private void ReturnMissileExplosionParticle(GameObject explosion) {
 0188    if (explosion == null) {
 0189      Debug.LogError("Attempted to return a null missile explosion particle");
 0190      return;
 191    }
 192
 0193    explosion.transform.parent = transform;
 0194    explosion.transform.localPosition = Vector3.zero;
 0195    ParticleSystem particleSystem = explosion.GetComponent<ParticleSystem>();
 0196    if (particleSystem != null) {
 0197      particleSystem.Stop();
 0198      particleSystem.Clear();
 0199    } else {
 0200      Debug.LogError("Attempted to return a missile explosion particle with no particle system");
 0201    }
 202
 0203    _missileExplosionPool.Enqueue(explosion);
 0204  }
 205
 0206  private GameObject InstantiateMissileTrail(GameObject prefab) {
 0207    GameObject trail = Instantiate(prefab, transform);
 0208    trail.GetComponent<ParticleSystem>().Stop();
 0209    _missileTrailPool.Enqueue(trail);
 0210    return trail;
 0211  }
 212
 0213  private GameObject InstantiateMissileExplosion(GameObject prefab) {
 0214    GameObject explosion = Instantiate(prefab, transform);
 0215    explosion.GetComponent<ParticleSystem>().Stop();
 0216    _missileExplosionPool.Enqueue(explosion);
 0217    return explosion;
 0218  }
 219
 220  private IEnumerator InstantiateMissileTrailsOverTime(GameObject prefab, int count,
 0221                                                       float duration) {
 0222    float interval = duration / count;
 0223    for (int i = 0; i < count; ++i) {
 0224      InstantiateMissileTrail(prefab);
 0225      yield return new WaitForSeconds(interval);
 0226    }
 0227  }
 228
 229  private IEnumerator InstantiateMissileExplosionsOverTime(GameObject prefab, int count,
 0230                                                           float duration) {
 0231    float interval = duration / count;
 0232    for (int i = 0; i < count; ++i) {
 0233      InstantiateMissileExplosion(prefab);
 0234      yield return new WaitForSeconds(interval);
 0235    }
 0236  }
 237
 238  /// Returns a missile trail particle prefab from the pool. If the pool is empty, it returns null.
 0239  public GameObject RequestMissileTrailParticle() {
 0240    if (_missileTrailPool.Count > 0 &&
 0241        SimManager.Instance.SimulatorConfig.EnableMissileTrailEffect) {
 0242      GameObject trail = _missileTrailPool.Dequeue();
 243
 0244      return trail;
 245    }
 0246    return null;
 0247  }
 248
 0249  public void ReturnMissileTrailParticle(GameObject trail) {
 0250    if (trail == null) {
 0251      Debug.LogError("Attempted to return a null missile trail particle");
 0252      return;
 253    }
 254
 0255    trail.transform.parent = transform;
 0256    trail.transform.localPosition = Vector3.zero;
 0257    ParticleSystem particleSystem = trail.GetComponent<ParticleSystem>();
 0258    if (particleSystem != null) {
 0259      particleSystem.Stop();
 0260      particleSystem.Clear();
 0261      var emission = particleSystem.emission;
 0262      emission.enabled = true;
 0263    } else {
 0264      Debug.LogError("Attempted to return a missile trail particle with no particle system");
 0265    }
 266
 0267    _missileTrailPool.Enqueue(trail);
 0268  }
 269}