Getting Shuriken Particles to Move to Target

Looked all over Google for a solution to this but it seems everyone hits a dead end in some way. So here I am asking again. I need to make the particles created by my Particle System move towards a target in world space. Here’s the script that I attached to the Particle System GameObject.

using UnityEngine;
using System.Collections;

public class ParticleAttraction : MonoBehaviour
{
    public ParticleSystem.Particle[] particles;
    public Transform target;

    void Start()
    {
       particles = new ParticleSystem.Particle[particleSystem.particleCount];
    }

    void Update()
    {
        particleSystem.GetParticles(particles);
        for (int i = 0; i < particles.Length; i++)
        {
            float distance = Vector3.Distance(target.position, particles[i].position);
            if (distance > 0.1f)
            {
                particles[i].position = Vector3.Lerp(particles[i].position, target.position, Time.deltaTime / 2.0f);
            }
        }
        particleSystem.SetParticles(particles, particles.Length);
    }
}

The problem is the particles just jump around wildly inside their emitter and die. They don’t actually move towards the target. In fact they’re dying as soon as they’re created.

Bump

Have you set the particle lifetime to a reasonable value? Are you simulating them in local or world space?

No matter what the lifetime is the result is the same… The same goes for both local and world space.

Is something in the particle system overwriting your changes to them? Maybe the particle system is doing its own simulation after you have modified the particles, overwritting your changes?

I’ll take a few minutes and see what I can do for you.

Not that I can see. I’ve been using the default Particle System for testing.

Thanks!

I didn’t really try your code, but I modified it to use the particle API properly:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(ParticleSystem))]
public class ParticleAttraction : MonoBehaviour
{
    public Transform Target;
   
    private ParticleSystem system;
   
    private static ParticleSystem.Particle[] particles = new ParticleSystem.Particle[1000];
   
    void Update()
    {
        if (system == null) system = GetComponent<ParticleSystem>();
       
        var count = system.GetParticles(particles);
       
        for (int i = 0; i < count; i++)
        {
            var particle = particles[i];
           
            float distance = Vector3.Distance(Target.position, particle.position);
           
            if (distance > 0.1f)
            {
                particle.position = Vector3.Lerp(particle.position, Target.position, Time.deltaTime / 2.0f);
               
                particles[i] = particle;
            }
        }
       
        system.SetParticles(particles, count);
    }
}

This code works fine for me, just keep in mind that your usage of Lerp and Time.deltaTime is incorrect and won’t produce delta time independent code.

@DRRosen3 I moved one line of code and changed the deltatime.time / 2.0f to deltatime.time * speed and it works for me :slight_smile: thanks.

 particles = new ParticleSystem.Particle[particleSystem.particleCount];

I put that line in update. done!. you need to know count each frame if the particle system is still spawning particles. Start only happens once and i noticed only a couple of the particles seemed to only go to to the target. so moving to update made it work for me.

and i put a public float speed; in the script so i can change how fast it goes to the locations. works great.

edit: oh and i got rid of lerp and used movetowards instead. i think this is also what fixes it. lerp i dont like.

This is really old, but wouldn’t it be more convenient to use MoveTowards? Perhaps that didn’t exist at the time this was written?

A solution I’m using is to have the particles explode outward, and then back inward. And then in code, you move the entire GameObject the particle system is on towards your target. Hope this helps future ppl.

1 Like
using UnityEngine;
using static UnityEngine.ParticleSystem;

public class ParticleTest : MonoBehaviour
{
    ParticleSystem pSystem;
    Particle[] particles;

    [SerializeField] Transform target;
    [SerializeField] float speed = 1f;
    [SerializeField] bool targetEnable = true;

    private void Start()
    {
        if (pSystem == null)
        {
            pSystem = GetComponent<ParticleSystem>();
            particles = new Particle[pSystem.main.maxParticles];
        }
    }

    private void Update()
    {
        if (targetEnable && target) Test_Particle();
    }

    void Test_Particle()
    {
        int length = pSystem.GetParticles(particles);

        for (int i = 0; i < length; i++)
        {
            Vector3 posA = particles[i].position;
            Vector3 posB = target.position - transform.position;

            if (Vector3.Distance(posA, posB) > 0.2f)
            {
                float variableSpeed = (pSystem.main.startSpeedMultiplier / (particles[i].remainingLifetime + 0.1f)) + particles[i].startLifetime;
                particles[i].position = Vector3.MoveTowards(posA, posB, variableSpeed * Time.deltaTime * speed);
            }
            else particles[i].remainingLifetime = -0.1f;
        }

        pSystem.SetParticles(particles, length);
    }
}