前几天一位实习生希望可以在脚本上控制粒子系统的粒子数,这个东西嘛 我当初也在试用期的时碰过一下。这些API都忘记的一干二净了。
所以搜了一下官方的API,经查后才发现,新版本的粒子系统API 都修改了,分成了不同的模块。UnityEngine.ParticleSystem – Unity 脚本 API
而事实上Unity官网也有实习生想要的效果(在EmissionModule.rateOverTime)
ParticleSystem-emission – Unity 脚本 API
但是我直接这样写发现会报错
void Update(){ emissionRate += 1; ps.emission.rateOverTime = new ParticleSystem.MinMaxCurve(emissionRate); }
因为ps.emssion 的类型是 EmissionModule, 而EmissionModule 是struct 而不是class。所以直接这样些就报错了。
过程中我也一直怀疑是不是Unity的文档太老旧了,抑或文档出错了?
因为按照直觉,因为 ps.emission 作为结构体,其已经是一个数据的副本。修改其数据再也不影响到粒子系统才对。
// Script interface for the EmissionModule of a Particle System. public struct EmissionModule { public bool enabled { get; set; } public MinMaxCurve rateOverTime { get; set; } public float rateOverTimeMultiplier { get; set; } public MinMaxCurve rateOverDistance { get; set; } public float rateOverDistanceMultiplier { get; set; } public int burstCount { get; set; } public Burst GetBurst(int index); public int GetBursts(Burst[] bursts); public void SetBurst(int index, Burst burst); public void SetBursts(Burst[] bursts); public void SetBursts(Burst[] bursts, int size); // ... Obsolete ... ignore }
但是Unity 就是这样,经过测试直接修改此emission 是可以控制粒子系统的。
其原理也很简单,估计在C++的部分还是隐藏了一个专门控制的句柄,只是在C#中没有显示出来。
例如
struct EmissionModule { private int handle; public int rate; void SetRate(){ var ps = GetPsInCpp(handle); ps.rate = this.rate; } }
在实际使用时,可以一直保存 emission, 在Update时不断调用也是可以的。
public class ParticleSystemController : MonoBehaviour { [SerializeField] new ParticleSystem particleSystem; [SerializeField] int emissionRate = 10; ParticleSystem.EmissionModule emissionModule; void Start(){ //var rot = particleSystem.emission.rateOverTime; var emission = particleSystem.emission; this.emissionModule = emission; } void Update() { //var emission = particleSystem.emission; var emission = this.emissionModule; emission.rateOverTime = new ParticleSystem.MinMaxCurve(emissionRate); } }
如果途中将Destroy(particleSystem)
此脚本会报错
NullReferenceException: Do not create your own module instances, get them from a ParticleSystem instance UnityEngine.ParticleSystem+EmissionModule.set_rateOverTime (UnityEngine.ParticleSystem+MinMaxCurve value) (at <893f889776d241068c95ad83f5452958>:0) ParticleSystemController.Update ()
可是看不出更深的调用堆栈。
那为什么不设计成class呢?我估计Unity 是希望不要存在太多的内存碎片。