• "反直觉" 的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 是希望不要存在太多的内存碎片。

  • 相关阅读:
    linux socket里的send和recv,阻塞与非阻塞socket、TCP与UDP在这方面的区别
    leetcode 149 Max Points on a Line
    leetcode 126 Word Ladder II
    leetcode 123 Best Time to Buy and Sell Stock III
    LC 297 Serialize and Deserialize Binary Tree
    栈和队列问题
    链表问题
    day17--权限管理和配置服务
    谷粒学院功能简介及系统架构
    day01--MybatisPlus的使用
  • 原文地址:https://www.cnblogs.com/godzza/p/15090717.html
Copyright © 2020-2023  润新知