Created
February 16, 2024 16:38
-
-
Save b3x206/6abf5a1b3f182479987a36842fffe2c1 to your computer and use it in GitHub Desktop.
A Unity Particle System particles attractor, useful for VFX/Other purposes.
This file contains 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
// ParticleAttractor.cs | |
// Attracts ParticleSystem particles towards given transform | |
// The code can be used for anything without attribution and it's from a part of 'Flag Race' | |
using Unity.Collections; | |
using UnityEngine; | |
using UnityEngine.Serialization; | |
/// <summary> | |
/// Attracts unity particle system (<see cref="ParticleSystem"/>) particles to given object <see cref="targetTransform"/>. | |
/// <br>Can be used on effects such as a powering up effect.</br> | |
/// <br/> | |
/// <br>Unlike most particle system attractors, this version doesn't allocate much C# heap garbage. This is because of the usage of 'NativeArray'.</br> | |
/// </summary> | |
[RequireComponent(typeof(ParticleSystem)), ExecuteAlways] | |
public class ParticleAttractor : MonoBehaviour | |
{ | |
public Transform targetTransform; | |
[SerializeField, FormerlySerializedAs("particleSystemAllocSize")] | |
private int m_ParticleSystemAllocSize = 256; | |
public int ParticleSystemAllocSize | |
{ | |
get => m_ParticleSystemAllocSize; | |
set | |
{ | |
m_ParticleSystemAllocSize = value; | |
// Resize array : | |
// There exists an extension to resize a NativeArray but i won't use that. | |
// This is because the particle system does not care about prior values (grug not care about value) | |
// grug want no GC Alloc in profiler | |
if (m_Particles.IsCreated) | |
{ | |
// We can discard the previous data as it's just going to be overwritten with something else. | |
m_Particles.Dispose(); | |
} | |
m_Particles = new NativeArray<ParticleSystem.Particle>(m_ParticleSystemAllocSize, Allocator.Persistent); | |
} | |
} | |
private ParticleSystem m_TargetParticleSystem; | |
private ParticleSystem TargetParticleSystem | |
{ | |
get | |
{ | |
if (m_TargetParticleSystem == null) | |
{ | |
m_TargetParticleSystem = GetComponent<ParticleSystem>(); | |
} | |
// Assert the 'simulationSpace' | |
ParticleSystem.MainModule main = m_TargetParticleSystem.main; | |
main.simulationSpace = ParticleSystemSimulationSpace.World; | |
return m_TargetParticleSystem; | |
} | |
} | |
/// <summary> | |
/// List of current manually managed particles. | |
/// </summary> | |
private NativeArray<ParticleSystem.Particle> m_Particles; | |
private void Start() | |
{ | |
if (!Application.isPlaying) | |
{ | |
return; | |
} | |
if (targetTransform == null) | |
{ | |
// Not a very important thing (to log), ignore as the transform parent could be the target object. | |
// Debug.Log($"[ParticleAttractor::Awake] Field 'targetTransform' was left blank on object '{this.GetPath()}'. Assigning self as the object."); | |
targetTransform = transform; | |
} | |
} | |
private void LateUpdate() | |
{ | |
if (!Application.isPlaying && targetTransform == null) | |
{ | |
return; // Don't do anything if it isn't running. | |
} | |
if (!m_Particles.IsCreated) | |
{ | |
m_Particles = new NativeArray<ParticleSystem.Particle>(m_ParticleSystemAllocSize, Allocator.Persistent); | |
} | |
if (TargetParticleSystem.isPlaying) | |
{ | |
int size = TargetParticleSystem.GetParticles(m_Particles); | |
Vector3 targetPos = targetTransform.position; | |
// --- | |
// Attraction behaviour can be customized here, you can use a 'Func<out ParticleSystem.Particle, in Vector3>' | |
// variable with a default interpolation (like in here) to make it changeable.. | |
// - | |
// This current behaviour makes the particle closer to the target transform's | |
// position depending on the lifetime remaining on the given particle. | |
// --- | |
for (int i = 0; i < size; i++) | |
{ | |
ParticleSystem.Particle setParticle = m_Particles[i]; | |
setParticle.position += (targetPos - setParticle.position) / setParticle.remainingLifetime * Time.deltaTime; | |
m_Particles[i] = setParticle; | |
} | |
// aabb / unrelated error(s) because we are putting invalid, default data to the SetParticles function. | |
// Because of this, always define the size on the 'SetParticles' | |
TargetParticleSystem.SetParticles(m_Particles, size); | |
} | |
} | |
private void OnDestroy() | |
{ | |
// Dispose the AllocationType.Persistent NativeArray | |
if (m_Particles.IsCreated) | |
{ | |
m_Particles.Dispose(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment