feat: ParticleAttractor supports multiple ParticleSystems

pull/336/head
dogramacigokhan 2024-07-07 11:05:42 +03:00 committed by mob-sakai
parent 686fff8690
commit a439248e1a
1 changed files with 99 additions and 74 deletions

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using Coffee.UIParticleExtensions; using Coffee.UIParticleExtensions;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
@ -22,7 +23,7 @@ namespace Coffee.UIExtensions
} }
[SerializeField] [SerializeField]
private ParticleSystem m_ParticleSystem; private List<ParticleSystem> m_ParticleSystems;
[Range(0.1f, 10f)] [Range(0.1f, 10f)]
[SerializeField] [SerializeField]
@ -45,7 +46,7 @@ namespace Coffee.UIExtensions
[SerializeField] [SerializeField]
private UnityEvent m_OnAttracted; private UnityEvent m_OnAttracted;
private UIParticle _uiParticle; private UIParticle[] _uiParticles;
public float destinationRadius public float destinationRadius
{ {
@ -84,25 +85,42 @@ namespace Coffee.UIExtensions
} }
/// <summary> /// <summary>
/// The target ParticleSystem to attract. /// The target ParticleSystems to attract. Use <see cref="AddParticleSystem"/> and
/// <see cref="RemoveParticleSystem"/> to modify the list.
/// </summary> /// </summary>
#if UNITY_EDITOR public IReadOnlyList<ParticleSystem> particleSystems => m_ParticleSystems;
public new ParticleSystem particleSystem
#else public void AddParticleSystem(ParticleSystem ps)
public ParticleSystem particleSystem
#endif
{ {
get => m_ParticleSystem; if (m_ParticleSystems == null)
set
{ {
m_ParticleSystem = value; m_ParticleSystems = new List<ParticleSystem>();
ApplyParticleSystem(); }
if (!m_ParticleSystems.Contains(ps))
{
m_ParticleSystems.Add(ps);
ApplyParticleSystems();
}
}
public void RemoveParticleSystem(ParticleSystem ps)
{
if (m_ParticleSystems == null)
{
return;
}
if (m_ParticleSystems.Contains(ps))
{
m_ParticleSystems.Remove(ps);
ApplyParticleSystems();
} }
} }
private void OnEnable() private void OnEnable()
{ {
ApplyParticleSystem(); ApplyParticleSystems();
UIParticleUpdater.Register(this); UIParticleUpdater.Register(this);
} }
@ -113,85 +131,95 @@ namespace Coffee.UIExtensions
private void OnDestroy() private void OnDestroy()
{ {
_uiParticle = null; _uiParticles = null;
m_ParticleSystem = null; m_ParticleSystems = null;
} }
internal void Attract() internal void Attract()
{ {
if (m_ParticleSystem == null) return; if (m_ParticleSystems == null) return;
var count = m_ParticleSystem.particleCount; for (var particleIndex = 0; particleIndex < this.m_ParticleSystems.Count; particleIndex++)
if (count == 0) return;
var particles = ParticleSystemExtensions.GetParticleArray(count);
m_ParticleSystem.GetParticles(particles, count);
var dstPos = GetDestinationPosition();
for (var i = 0; i < count; i++)
{ {
// Attracted var particleSystem = m_ParticleSystems[particleIndex];
var p = particles[i]; if (particleSystem == null || !particleSystem.gameObject.activeInHierarchy) continue;
if (0f < p.remainingLifetime && Vector3.Distance(p.position, dstPos) < m_DestinationRadius)
{
p.remainingLifetime = 0f;
particles[i] = p;
if (m_OnAttracted != null) var count = particleSystem.particleCount;
if (count == 0) continue;
var particles = ParticleSystemExtensions.GetParticleArray(count);
particleSystem.GetParticles(particles, count);
var uiParticle = this._uiParticles != null && particleIndex < _uiParticles.Length
? _uiParticles[particleIndex]
: null;
var dstPos = this.GetDestinationPosition(uiParticle, particleSystem);
for (var i = 0; i < count; i++)
{
// Attracted
var p = particles[i];
if (0f < p.remainingLifetime && Vector3.Distance(p.position, dstPos) < this.m_DestinationRadius)
{ {
try p.remainingLifetime = 0f;
particles[i] = p;
if (this.m_OnAttracted != null)
{ {
m_OnAttracted.Invoke(); try
} {
catch (Exception e) this.m_OnAttracted.Invoke();
{ }
Debug.LogException(e); catch (Exception e)
{
Debug.LogException(e);
}
} }
continue;
} }
continue; // Calc attracting time
var delayTime = p.startLifetime * this.m_DelayRate;
var duration = p.startLifetime - delayTime;
var time = Mathf.Max(0, p.startLifetime - p.remainingLifetime - delayTime);
// Delay
if (time <= 0) continue;
// Attract
p.position = this.GetAttractedPosition(p.position, dstPos, duration, time);
p.velocity *= 0.5f;
particles[i] = p;
} }
// Calc attracting time particleSystem.SetParticles(particles, count);
var delayTime = p.startLifetime * m_DelayRate;
var duration = p.startLifetime - delayTime;
var time = Mathf.Max(0, p.startLifetime - p.remainingLifetime - delayTime);
// Delay
if (time <= 0) continue;
// Attract
p.position = GetAttractedPosition(p.position, dstPos, duration, time);
p.velocity *= 0.5f;
particles[i] = p;
} }
m_ParticleSystem.SetParticles(particles, count);
} }
private Vector3 GetDestinationPosition() private Vector3 GetDestinationPosition(UIParticle uiParticle, ParticleSystem particleSystem)
{ {
var isUI = _uiParticle && _uiParticle.enabled; var isUI = uiParticle && uiParticle.enabled;
var psPos = m_ParticleSystem.transform.position; var psPos = particleSystem.transform.position;
var attractorPos = transform.position; var attractorPos = transform.position;
var dstPos = attractorPos; var dstPos = attractorPos;
var isLocalSpace = m_ParticleSystem.IsLocalSpace(); var isLocalSpace = particleSystem.IsLocalSpace();
if (isLocalSpace) if (isLocalSpace)
{ {
dstPos = m_ParticleSystem.transform.InverseTransformPoint(dstPos); dstPos = particleSystem.transform.InverseTransformPoint(dstPos);
} }
if (isUI) if (isUI)
{ {
var inverseScale = _uiParticle.parentScale.Inverse(); var inverseScale = uiParticle.parentScale.Inverse();
var scale3d = _uiParticle.scale3DForCalc; var scale3d = uiParticle.scale3DForCalc;
dstPos = dstPos.GetScaled(inverseScale, scale3d.Inverse()); dstPos = dstPos.GetScaled(inverseScale, scale3d.Inverse());
// Relative mode // Relative mode
if (_uiParticle.positionMode == UIParticle.PositionMode.Relative) if (uiParticle.positionMode == UIParticle.PositionMode.Relative)
{ {
var diff = _uiParticle.transform.position - psPos; var diff = uiParticle.transform.position - psPos;
diff.Scale(scale3d - inverseScale); diff.Scale(scale3d - inverseScale);
diff.Scale(scale3d.Inverse()); diff.Scale(scale3d.Inverse());
dstPos += diff; dstPos += diff;
@ -237,25 +265,22 @@ namespace Coffee.UIExtensions
return Vector3.MoveTowards(current, target, speed); return Vector3.MoveTowards(current, target, speed);
} }
private void ApplyParticleSystem() private void ApplyParticleSystems()
{ {
_uiParticle = null; _uiParticles = null;
if (m_ParticleSystem == null) if (m_ParticleSystems == null || m_ParticleSystems.Count == 0)
{ {
#if UNITY_EDITOR
if (Application.isPlaying)
#endif
{
Debug.LogError("No particle system attached to particle attractor script", this);
}
return; return;
} }
_uiParticle = m_ParticleSystem.GetComponentInParent<UIParticle>(true); _uiParticles = new UIParticle[m_ParticleSystems.Count];
if (_uiParticle && !_uiParticle.particles.Contains(m_ParticleSystem)) for (var i = 0; i < this.m_ParticleSystems.Count; i++)
{ {
_uiParticle = null; var particleSystem = m_ParticleSystems[i];
if (particleSystem == null) continue;
var uiParticle = particleSystem.GetComponentInParent<UIParticle>(true);
_uiParticles[i] = uiParticle.particles.Contains(particleSystem) ? uiParticle : null;
} }
} }
} }