zoukankan      html  css  js  c++  java
  • "反直觉" 的Unity粒子系统API

    前几天一位实习生希望可以在脚本上控制粒子系统的粒子数,这个东西嘛 我当初也在试用期的时碰过一下。这些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 是希望不要存在太多的内存碎片。

  • 相关阅读:
    luogu_1659【题解】manacher 啦啦队排练
    manacher算法
    luogu_4503【题解】企鹅QQ 哈希
    luogu_3966【题解】单词 AC自动机
    字符串 AC自动机
    luogu_3275【题解】糖果 差分约束
    luogu_4568 飞行路线 分层图
    luogu_4551【题解】最长异或路径 trie树
    luogu_1041【题解】搜索 传染病控制
    [题解/模板]扫描线
  • 原文地址:https://www.cnblogs.com/godzza/p/15090717.html
Copyright © 2011-2022 走看看