Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
143 views
in Technique[技术] by (71.8m points)

c# - Understanding the "Struct" in Unity ParticleSystem

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...