using UnityEngine;
using Unity.Mathematics;
using UnityEngine.SceneManagement;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Unity.MegaCity.Gameplay
{
///
/// Manages the laser pool
///
public class LaserPool : MonoBehaviour
{
public static LaserPool Instance;
[Header("Laser Renderer")]
[SerializeField] private GameObject Renderer;
[Header("Particle Systems")]
[SerializeField] private GameObject LaserBeam;
[SerializeField] private GameObject LaserHit;
[SerializeField] private float m_Speed = 25f;
[SerializeField] private float m_MaxDistanceFactorPerSpeed = 25f;
[SerializeField] private int m_MaxPlayers = 256;
private LineRenderer[] m_LaserPool;
private ParticleSystem[] m_LaserBeamPool;
private ParticleSystem[] m_LaserHitPool;
private AudioSource[] m_LaserBeamAudioPool;
private int m_ActiveLines;
private int m_PrevActiveLines;
// TODO: Instantiate initial pool size and grow the pool on demand
//private int m_InitialPoolSize = 4;
private Scene AdditiveScene;
public void BeginUpdate()
{
m_PrevActiveLines = m_ActiveLines;
m_ActiveLines = 0;
}
public void EndUpdate()
{
for (var i = m_PrevActiveLines; i < m_ActiveLines; ++i)
{
m_LaserPool[i].enabled = true;
m_LaserBeamPool[i].Play(true);
m_LaserHitPool[i].Play(true);
if(!m_LaserBeamAudioPool[i].isPlaying)
m_LaserBeamAudioPool[i].Play();
}
for (var i = m_ActiveLines; i < m_PrevActiveLines; ++i)
{
m_LaserPool[i].enabled = false;
m_LaserBeamPool[i].Stop(true);
m_LaserHitPool[i].Stop(true);
if(m_LaserBeamAudioPool[i].isPlaying)
m_LaserBeamAudioPool[i].Stop();
}
}
public void AddLine(float3 start, float3 end, float currentSpeed)
{
var distance = math.distance(m_LaserPool[m_ActiveLines].GetPosition(0), start);
var shouldPlace = currentSpeed <= 0 && distance > 1;
// if the distance is long should place it quickly otherwise it should only smooth the position
if (distance > (currentSpeed * m_MaxDistanceFactorPerSpeed) || shouldPlace)
Place(start, end);
// Set Line Renderer
var speed = Time.deltaTime * m_Speed;
var offset = (end - start) / 4;
var pos0 = math.lerp(m_LaserPool[m_ActiveLines].GetPosition(0), start, speed);
var pos1 = math.lerp(m_LaserPool[m_ActiveLines].GetPosition(1), start + offset, speed);
var pos2 = math.lerp(m_LaserPool[m_ActiveLines].GetPosition(2), end - offset, speed);
var pos3 = math.lerp(m_LaserPool[m_ActiveLines].GetPosition(3), end, speed);
m_LaserPool[m_ActiveLines].SetPosition(0, pos0);
m_LaserPool[m_ActiveLines].SetPosition(1, pos1);
m_LaserPool[m_ActiveLines].SetPosition(2, pos2);
m_LaserPool[m_ActiveLines].SetPosition(3, pos3);
// Set LaserBeam position
var newPos = math.lerp(m_LaserBeamPool[m_ActiveLines].transform.position, start, speed);
var rotation = Quaternion.Lerp(m_LaserBeamPool[m_ActiveLines].transform.rotation, Quaternion.LookRotation(end - start), speed);
m_LaserBeamPool[m_ActiveLines].transform.SetPositionAndRotation(newPos, rotation);
var endPos = math.lerp(m_LaserHitPool[m_ActiveLines].transform.position, end, speed);
m_LaserHitPool[m_ActiveLines].transform.position = endPos;
m_ActiveLines++;
}
private void Place(float3 start, float3 end)
{
var offset = (end - start) / 4;
m_LaserPool[m_ActiveLines].SetPosition(0, start);
m_LaserPool[m_ActiveLines].SetPosition(1, start + offset);
m_LaserPool[m_ActiveLines].SetPosition(2, end - offset);
m_LaserPool[m_ActiveLines].SetPosition(3, end);
m_LaserBeamPool[m_ActiveLines].transform
.SetPositionAndRotation(start, Quaternion.LookRotation(end - start));
m_LaserHitPool[m_ActiveLines].transform.position = end;
}
private void Awake()
{
if (Instance != null)
{
Destroy(gameObject);
}
else
{
Instance = this;
}
}
private void Start()
{
#if UNITY_EDITOR
if (!EditorApplication.isPlayingOrWillChangePlaymode)
AdditiveScene = SceneManager.GetSceneByName("AdditiveLaserPoolScene");
else
#endif
AdditiveScene = SceneManager.CreateScene("AdditiveLaserPoolScenePlaymode");
// Initialize pools
m_LaserPool = new LineRenderer[m_MaxPlayers];
m_LaserBeamPool = new ParticleSystem[m_MaxPlayers];
m_LaserHitPool = new ParticleSystem[m_MaxPlayers];
m_LaserBeamAudioPool = new AudioSource[m_MaxPlayers];
// Allocate initial pools
for (var i = 0; i < m_MaxPlayers; ++i)
{
AllocateLaser(i);
}
}
private void AllocateLaser(int index)
{
var laser = Instantiate(Renderer);
m_LaserPool[index] = laser.GetComponent();
m_LaserPool[index].enabled = false;
laser.SetActive(true);
SceneManager.MoveGameObjectToScene(laser, AdditiveScene);
var laserBeam = Instantiate(LaserBeam);
m_LaserBeamPool[index] = laserBeam.GetComponent();
m_LaserBeamPool[index].Pause(true);
laserBeam.SetActive(true);
var laserAudioSource = laserBeam.GetComponent();
m_LaserBeamAudioPool[index] = laserAudioSource;
SceneManager.MoveGameObjectToScene(laserBeam, AdditiveScene);
var laserHit = Instantiate(LaserHit);
m_LaserHitPool[index] = laserHit.GetComponent();
m_LaserHitPool[index].Pause(true);
laserHit.SetActive(true);
SceneManager.MoveGameObjectToScene(laserHit, AdditiveScene);
}
private void OnDestroy()
{
if (Instance == this)
Instance = null;
}
}
}