So I was tasked to make a particle system follow a set of points (P1, P2, P3, … Pn) for a visualization in the CAVE. Basically given a particle system, make the particles in it follow a set of points:
If we linearly interpolate their positions through a group of points we will get a set of particles that will follow a set of points, something like this:
Instead what we want is to make each spawned particle follow a set of directions, something like this:
So in order to achieve this, we create an array of directions (given the points), then we check the total distance traveled for each particle and then depending on where the particle is located (across the points) we change the direction accordingly towards the next point (when it reaches each point)
The end result:
The Code:
The code is pretty straight forward; one editor script and one simple script that needs to be attached to a game object that contains the particle system.
Editor Script: (remember to place it under “Editor” folder).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
/* This class draws the handles for the diferent nodes the particles are going to follow. created by: Juan Sebastian Munoz Arango 2015 */ using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; [CustomEditor(typeof(Follower))] public class FollowerCustomEditor : Editor { private Follower myTarget = null; private const int offset = 50;//offset when creating a new node. void OnEnable() { myTarget = (Follower) target; if(myTarget.nodes == null) { myTarget.nodes = new List<Vector3>(); myTarget.nodes.Add(myTarget.transform.position + Random.insideUnitSphere*offset); } } void OnSceneGUI() { if(myTarget != null) { for(int i = 0; i < myTarget.nodes.Count; i++) { myTarget.nodes[i] = Handles.PositionHandle(myTarget.nodes[i], Quaternion.identity); } } } public override void OnInspectorGUI() { for(int i = 0; i < myTarget.nodes.Count; i++) { GUILayout.BeginHorizontal(); myTarget.nodes[i] = EditorGUILayout.Vector3Field("", myTarget.nodes[i]); if(GUILayout.Button("X")) { if(myTarget.nodes.Count > 1) myTarget.nodes.RemoveAt(i); } GUILayout.EndHorizontal(); } if(GUILayout.Button("Add")) { Vector3 newPos = myTarget.nodes[myTarget.nodes.Count-1] + Random.insideUnitSphere*offset; myTarget.nodes.Add(newPos); } } } |
The script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/* Created by: Juan Sebastian Munoz arango 2015 Simple particle system that follows certain o */ using UnityEngine; using System.Collections; using System.Collections.Generic; public class Follower : MonoBehaviour { public List<Vector3> nodes; private Vector3[] directions; void Start() { GetComponent<ParticleSystem>().startLifetime = nodes.Count; if(nodes.Count == 0) Debug.LogError("Nodes needs to have at least 1 item"); directions = new Vector3[nodes.Count]; for(int i = 0; i < nodes.Count; i++) { directions[i] = (nodes[i] - ((i-1 >= 0) ? nodes[i-1] : transform.position)); } } void Update() { ParticleSystem p = (ParticleSystem) GetComponent<ParticleSystem>(); ParticleSystem.Particle[] particleList = new ParticleSystem.Particle[p.particleCount]; int partCount = GetComponent<ParticleSystem>().GetParticles(particleList); for(int i = 0; i < partCount; i++) { float timeAlive = particleList[i].startLifetime - particleList[i].lifetime; float dist = GetAddedMagnitude((int)(timeAlive)); int count = 0; while(dist > GetAddedMagnitude(count)) count++; particleList[i].velocity = directions[count]; } p.SetParticles(particleList, partCount); } private float GetAddedMagnitude(int count) { float addedMagnitude = 0; for(int i = 0; i < count; i++) { addedMagnitude += directions[i].magnitude; } return addedMagnitude; } private void OnDrawGizmosSelected() { Gizmos.color = Color.green; Gizmos.DrawLine(transform.position, nodes[0]); for(int i = 1; i < nodes.Count; i++) { Gizmos.DrawLine(nodes[i], nodes[i-1]); } } } |
Still there is some stuff missing like adding speed to the particles or making the generated pivots move relative to the game object but it pretty much does the job.
Good!