The code below is working, "Particle" is an instance of class "ParticleSystem".
"Particle.emission" is a get-only property return struct "ParticleSystem.EmissionModule"
"em.rate" is a property, the type is struct "ParticleSystem.MinMaxCurve"
ParticleSystem.EmissionModule em = Particle.emission;
em.rate = new ParticleSystem.MinMaxCurve(5);
My problem is, why the code above can change the rate in "Particle" instance?
Note the struct is not reference, so it cannot be changed directly, or it will cause CS1612
Currently, my guess is the struct "ParticleSystem.EmissionModule" stored some references that can link or relate to the original "Particle" instance?
I noticed this behavior too but I found out what's happening after digging deeper with .NET Reflector.
The complete example of your code with the latest Unity version:
ParticleSystem particle = GetComponent<ParticleSystem>();
ParticleSystem.EmissionModule em = particle.emission;
em.rate = new ParticleSystem.MinMaxCurve(5);
Things to bear in mind:
ParticleSystem
is a class
.
EmissionModule
is a struct
.
To change the Particle's emission rate in Unity 5 and above, you must get the ParticleSystem.emission
then store it in a temporary EmissionModule
(struct) then you can modify it's rate
variable
How does this work?
When you do:
ParticleSystem particle = GetComponent<ParticleSystem>();
or create/instantiate new ParticleSystem
or attach one through the Editor, Unity will create new EmissionModule
instance. EmissionModule
has a an internal
constructor that takes ParticleSystem
as a parameter. Unity will immediately pass the current ParticleSystem
instance to this EmissionModule
constructor and that instance is stored in a temporary variable in the EmissionModule
struct for later use.
It looks something like this:
private ParticleSystem tempParticleSystem;
internal EmissionModule(ParticleSystem particleInstance)
{
this.tempParticleSystem = particleInstance;
}
When you do:
ParticleSystem.EmissionModule em = particle.emission;
Unity will create new instance of EmissionModule
from the current particle (particle
) and return it. That will contain that ParticleSystem
(tempParticleSystem) reference that was saved. Remember that ParticleSystem
is a class, so the reference is still there. The emission
property only have the get
accessor. No set
accessor. Because of this, it is a read only property.
The emission
property looks something like this:
public EmissionModule emission
{
get
{
return new EmissionModule(this);
}
}
Finally, when the you do:
em.rate = ....
or change the emission rate, that saved reference is used to change the Particle rate in the native side of Unity which is written in C++.
public ParticleSystem.MinMaxCurve rate
{
get
{
ParticleSystem.MinMaxCurve curve = new ParticleSystem.MinMaxCurve();
getParticleRate(this.tempParticleSystem, ref curve);
return curve;
}
set
{
setParticleRate(this.tempParticleSystem, ref value);
}
}
To simplify this, we can call this a result of a class
(ParticleSystem
) inside a struct
(EmissionModule
).