Hello, my particle sys only emits 1 particle at a time. What I’m trying to do is: After it collides with my hero, I will turn collision off, then I want the particle to continue its path. The script indeed turns off collision and adjusts velocity of the particle, however after the particle collides with the hero, no option I’ve tried will ever make it resume back its speed, script or non-script even. Any help? Thanks.
Here is also my simple code.
public class PArticles : MonoBehaviour
{
public float particleSpeed = 5f; // Adjust as needed
private ParticleSystem particleSystem;
void Start()
{
particleSystem = GetComponent<ParticleSystem>();
}
void OnParticleCollision(GameObject other)
{
//Turn off collision
ChangeCol();
//Velocity Restore
ParticleSystem.Particle[] particles = new ParticleSystem.Particle[particleSystem.particleCount];
int numParticlesAlive = particleSystem.GetParticles(particles);
for (int i = 0; i < numParticlesAlive; i++)
{
// Example: Make particles continue their path by adjusting velocity
particles[i].velocity = particles[i].velocity.normalized * particleSpeed;
}
//Update propeties of the particles
particleSystem.SetParticles(particles, numParticlesAlive);
Debug.Log(other.name);
}
void ChangeCol()
{
var collisionModule = particleSystem.collision;
collisionModule.enabled = false;
}
}
It seems the particle already reacts to collision before OnParticleCollision is called.
What you could do is keep track of the particles velocity in update, then when the collision occurs, just assign the last velocity to the particle.
public Vector3[] lastVel;
void Update()
{
ParticleSystem.Particle[] particles = new ParticleSystem.Particle[particleSystem.particleCount];
int numParticlesAlive = particleSystem.GetParticles (particles);
for (int i = 0; i < numParticlesAlive; i++) {
lastVel [i] = particles [i].velocity;
}
}
void OnParticleCollision (GameObject other)
{
//Turn off collision
ChangeCol ();
//Velocity Restore
ParticleSystem.Particle[] particles = new ParticleSystem.Particle[particleSystem.particleCount];
int numParticlesAlive = particleSystem.GetParticles (particles);
for (int i = 0; i < numParticlesAlive; i++) {
particles [i].velocity = lastVel [i];
}
//Update propeties of the particles
particleSystem.SetParticles (particles, numParticlesAlive);
}
Note: this code might need some optimizations for performance
1 Like
Thanks, works fine now, I also noticed mistake in my code there is actually multiplication by zero, but I hadn’t caught it before.
When you do stuff like this in code:
… you are setting yourself up for mass confusion when you change that 5f and (amazingly!) nothing changes in your scene.
Here’s why:
Serialized / public fields in Unity are initialized as a cascade of possible values, each subsequent value (if present) overwriting the previous value:
-
what the class constructor makes (either default(T) or else field initializers, eg “what’s in your code”)
-
what may be saved with the prefab
-
what may be saved with the prefab override(s)/variant(s)
-
what may be saved in the scene and not applied to the prefab
-
what may be changed in the scene and not yet saved to disk
-
what may be changed in OnEnable(), Awake(), Start(), or even later
Make sure you only initialize things at ONE of the above levels, or if necessary, at levels that you specifically understand in your use case. Otherwise errors will seem very mysterious.
Here’s the official discussion: https://blog.unity.com/technology/serialization-in-unity
If you must initialize fields, then do so in the void Reset()
method, which ONLY runs in the UnityEditor.
Field initializers versus using Reset() function and Unity serialization:
https://discussions.unity.com/t/829681/2
https://discussions.unity.com/t/846251/8
To avoid complexity in your prefabs / scenes, I recommend NEVER using the FormerlySerializedAsAttribute