using UnityEngine; using System.Collections.Generic; namespace Neatly.UI { [RequireComponent(typeof(RectTransform))] public class NParticleSystem : MonoBehaviour { #region Inspector public bool showParticleSystem = false; public bool showEmission = false; public bool showShape = false; public bool showSize = false; public bool showColor = false; public bool showRotate = false; public bool showVelocityOverLifeTime = false; public bool showForceOverLifeTime = false; public bool enableSize = false; public bool enableColor = false; public bool enableRotate = false; public bool enableVelocity = false; public bool enableForce = false; #endregion public enum Shape { Rect, Circle, } public enum EmissionShapeType { Sector, Circle, } #region ParticleSystem [SerializeField] private Sprite m_Sprite; [SerializeField] private Material m_Material; [SerializeField] private Shape m_ShapeType; [SerializeField] [Range(0, 99)] private float m_StartDelay = 0; [SerializeField] [Range(0, 99)] private float m_StartLifetime = 5; [SerializeField] [Range(0, 1)] private float m_RandLifeRatio = 0; [SerializeField] private float m_StartSpeed = 1; [SerializeField] [Range(0, 1)] private float m_RandSpeedRatio = 0; [SerializeField] private Vector2 m_StartSize = Vector2.one * 20; [SerializeField] private Color m_Color = Color.white; [SerializeField] [Range(1, 2000)] private int m_MaxParticles = 10; private float m_SizeMin; private float m_SizeMax; #endregion #region Emission //Count per Time [SerializeField] private float m_RateOverTime = 2; // Please wait... [SerializeField] private float m_RateOverDistance; //base Time. private const float m_EmissionBaseTime = 1; private float m_EmissionDeltaTime; private float m_EmissionTotalTime = 0; #endregion #region Shape [SerializeField] private EmissionShapeType m_EmissionShape = EmissionShapeType.Sector; public EmissionShapeType EmissionEmissionShape { get { return m_EmissionShape; } } [SerializeField] [Range(0, 360)] private int m_Angle; #endregion #region Velocity [SerializeField] private Vector2 m_Velocity = Vector2.zero; [SerializeField] [Range(0, 1)] private float m_RandVelocityRatio = 0; #endregion #region Force [SerializeField] private Vector2 m_Force = Vector2.zero; [SerializeField] [Range(0, 1)] private float m_RandForceRatio = 0; #endregion #region Color [SerializeField] private Color m_FinalColor = Color.white; #endregion #region Size [SerializeField] private Vector2 m_FinalSize = Vector2.zero; #endregion #region Property private Vector2 m_Position; private RectTransform m_RectTransform; private List m_ParticleList = new List(); private List m_CacheParticleList = new List(); private float m_HalfWidth; private float m_HalfHeight; private int m_HalfAngle; private float m_LifeMin; private float m_LifeMax; private float m_SpeedMin; private float m_SpeedMax; private Vector2 m_RandPosition = Vector2.zero; private Vector2 m_RandDirect = Vector2.zero; private float m_RandLifeTime = 0; private float m_RandSpeed = 0; private Vector2 m_RandVelocity = Vector2.zero; private Vector2 m_RandForce = Vector2.zero; private byte m_CurrentCount; #endregion void Start() { Init(); } void Init() { if (m_EmissionShape == EmissionShapeType.Circle) { m_Angle = 360; } m_RectTransform = transform as RectTransform; m_Position = m_RectTransform.anchoredPosition; m_HalfWidth = m_RectTransform.rect.width / 2; m_HalfHeight = m_RectTransform.rect.height / 2; m_HalfAngle = m_Angle / 2; m_LifeMin = m_StartLifetime - m_StartLifetime * m_RandLifeRatio; m_LifeMax = m_StartLifetime + m_StartLifetime * m_RandLifeRatio; m_SpeedMin = m_StartSpeed - m_StartSpeed * m_RandSpeedRatio; m_SpeedMax = m_StartSpeed + m_StartSpeed * m_RandSpeedRatio; m_EmissionDeltaTime = m_EmissionBaseTime / m_RateOverTime; } void DoEmission(float deltaTime) { m_EmissionTotalTime += deltaTime; if (m_EmissionTotalTime <= m_EmissionDeltaTime) return; //get sprite from cache var effectSprite = GetEffectSprite(); // in max if (effectSprite == null) return; effectSprite.Show(); //Random position RandPosDirectSpeed(); effectSprite.SetStartInfo(m_RandPosition, m_StartSize, m_RandLifeTime, m_RandDirect, m_RandSpeed); //set sprite and material , Color effectSprite.SetSpriteInfo(m_Sprite, m_Material, m_Color); if (enableVelocity) { effectSprite.AddVelocity(m_RandVelocity); } if (enableForce) { effectSprite.AddForce(m_RandForce); } if (enableColor) { effectSprite.AddColorTween(m_FinalColor); } if (enableSize) { effectSprite.AddSizeTween(m_FinalSize); } m_EmissionTotalTime = 0; m_ParticleList.Add(effectSprite); } private EffectImage GetEffectSprite() { EffectImage effectImage; if (m_CacheParticleList.Count > 0) { int index = m_CacheParticleList.Count - 1; effectImage = m_CacheParticleList[index]; m_CacheParticleList.RemoveAt(index); return effectImage; } if (m_CurrentCount >= m_MaxParticles) return null; m_CurrentCount++; effectImage = NParticlePool.Instance.Create(); effectImage.transform.SetParent(transform); effectImage.rectTransform.SetAnchoredPosition3DOne(0); effectImage.transform.SetLocalScaleOne(0); return effectImage; } /// /// Reset Emission Position. /// /// private void RandPosDirectSpeed() { float posX = Random.Range(- m_HalfWidth, m_HalfWidth); float posY = Random.Range(- m_HalfHeight, m_HalfHeight); m_RandPosition.x = posX; m_RandPosition.y = posY; int randomAngle = Random.Range(-m_HalfAngle, m_HalfAngle); float directX = Mathf.Sin(Mathf.Deg2Rad * randomAngle) * 10; float directY = Mathf.Cos(Mathf.Deg2Rad * randomAngle) * 10; m_RandDirect.x = directX; m_RandDirect.y = directY; m_RandLifeTime = Random.Range(m_LifeMin, m_LifeMax); m_RandSpeed = Random.Range(m_SpeedMin, m_SpeedMax); if (enableVelocity) { float ratioX = m_Velocity.x * m_RandVelocityRatio; float ratioY = m_Velocity.y * m_RandVelocityRatio; m_RandVelocity.x = Random.Range(m_Velocity.x - ratioX, m_Velocity.x + ratioX); m_RandVelocity.y = Random.Range(m_Velocity.y - ratioY, m_Velocity.y + ratioY); } if (enableForce) { float ratioX = m_Force.x * m_RandForceRatio; float ratioY = m_Force.y * m_RandForceRatio; m_RandForce.x = Random.Range(m_Force.x - ratioX, m_Force.x + ratioX); m_RandForce.y = Random.Range(m_Force.y - ratioY, m_Force.y + ratioY); } } bool m_IsPause = false; public void Pause() { m_IsPause = true; } public void Resume() { m_IsPause = false; } void Update() { if (m_IsPause) return; for (int i = m_ParticleList.Count - 1; i >= 0; i--) { var effectSprite = m_ParticleList[i]; bool isFinish = effectSprite.ParticleUpdate(Time.deltaTime); if (isFinish) { effectSprite.Hide(); m_ParticleList.RemoveAt(i); m_CacheParticleList.Add(effectSprite); } } DoEmission(Time.deltaTime); } // void OnEnable() // { // Reset(); // } // // void OnDisable() // { // for (int i = m_CacheParticleList.Count-1; i >=0; i--) // { // var effectSprite = m_CacheParticleList[i]; // m_CacheParticleList.RemoveAt(i); // SDParticlePool.Instance.Recycle(effectSprite); // } // for (int i = m_ParticleList.Count - 1; i >= 0; i--) // { // var effectSprite = m_ParticleList[i]; // m_ParticleList.RemoveAt(i); // SDParticlePool.Instance.Recycle(effectSprite); // } // Reset(); // } // void Reset() // { // m_CurrentCount = 0; // m_EmissionTotalTime = 0; // } // void OnDrawGizmosSelected() { } #if UNITY_EDITOR /// /// Reset System and Restart. Only in Editor /// public void Restart() { // for (int i = m_ParticleList.Count - 1; i >= 0; i--) { var effectSprite = m_ParticleList[i]; m_ParticleList.RemoveAt(i); DestroyImmediate(effectSprite.gameObject); } for (int i = m_CacheParticleList.Count - 1; i >= 0; i--) { var effectSprite = m_CacheParticleList[i]; m_CacheParticleList.RemoveAt(i); DestroyImmediate(effectSprite.gameObject); } Init(); } #endif } }