1. 程式人生 > >模擬粒子系統(ParticleSystem.Simulate)

模擬粒子系統(ParticleSystem.Simulate)

using UnityEngine;
using UnityEditor;
[ExecuteInEditMode]
public class MyWindow : EditorWindow
{
    private GameObject _curEffect;

    private float _curValue = 0;

    private float _preTime;

    private bool _isRun;

    private float _totalTime = 3.0f;

    private ParticleSystem[] _psList = null;

    [MenuItem("Window/My Window")]
    static void Init()
    {
        MyWindow window = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow));
        window.Show();
    }

    void OnEnable()
    {
        _preTime = Time.realtimeSinceStartup;
        EditorApplication.update += EditorUpdate;
    }

    void Disable()
    {
        EditorApplication.update -= EditorUpdate;
    }

    void OnGUI()
    {
        GameObject obj = EditorGUILayout.ObjectField("object", _curEffect, typeof(GameObject)) as GameObject;

        if (obj != _curEffect)
        {
            _curEffect = obj;

            if (_curEffect != null)
            {
                _psList = _curEffect.GetComponentsInChildren<ParticleSystem>(true);
            }
            else
            {
                _psList = null;
            }
             
        }

        float value = EditorGUILayout.Slider("value", _curValue, 0, _totalTime);
        if (value != _curValue)
        {
            _curValue = value;
            foreach (ParticleSystem ps in _psList)
            {
                ps.Simulate(0, false, true);
                ps.time = 0;
                ps.Play();
            }

            for (float i = 0.0f; i < _curValue; i += 0.02f)
            {    
                SimsimulateParticlesForDeltaTime(0.02f);
            }
        }

        if (GUILayout.Button("播放"))
        {
            if (_psList != null)
            {
                foreach (ParticleSystem ps in _psList)
                {
                    ps.time = 0;
                    ps.Play();
                }
            }
            
            _preTime = Time.realtimeSinceStartup;
            _isRun = true;
            _curValue = 0;
        }
    }

    /*
    // 有問題,用curTime用模擬就有問題
    void SimsimulateParticlesForTotoleTime(float curTime)
    {
        if (_curEffect != null)
        {
            ParticleSystem[] psList = _curEffect.GetComponentsInChildren<ParticleSystem>(true);

            foreach (ParticleSystem ps in psList)
            {
                
                ps.Play();
                ps.time = 0;
                ps.Simulate(curTime, false, true);
            }

        }
    }
    */

    // DeltaTime,去模擬不會有問題
    void SimsimulateParticlesForDeltaTime(float deltaTime)
    {
        if (_psList != null)
        {
            foreach (ParticleSystem ps in _psList)
            {
                ps.Simulate(deltaTime, false, false);
            }

        }
    }

    void EditorUpdate()
    {
        if (_isRun)
        {
            float deltaTime = Time.realtimeSinceStartup - _preTime;
            _preTime = Time.realtimeSinceStartup;
            _curValue += deltaTime;
            if (_curValue >= _totalTime)
            {
                _curValue = 0;
                _isRun = false;
                Debug.Log("Finish");
            }
            SimsimulateParticlesForDeltaTime(deltaTime);
            //SimsimulateParticlesForTotoleTime(_curValue);
            
        }

        SceneView.RepaintAll();
        GameViewRepaint(Camera.main);
    }

    private void GameViewRepaint(Camera camera)
    {
        if (camera)
        {
            Rect cameraRect = new Rect(0, 0, UnityEngine.Screen.width, UnityEngine.Screen.height);
            Rect cameraOriginalRect = camera.pixelRect;
            camera.pixelRect = cameraRect;
            camera.Render();
            camera.pixelRect = cameraOriginalRect;
        }

    }
}

The function documentation states:

function Simulate (deltaTime : float) : void

That is, the function parameter is a time delta, a step in time. It is not a certain moment in time.

Physical simulations work based on discrete steps in time. And the stability of many simulations (or rather the error within a simulation) is directly related to the size of a time step you take.

In your code, you're taking increasingly large steps in time. While single particles might put up with that for a while, given a sufficiently large step they might start to become unstable.

Most likely your problem will be resolved by taking a number of fixed time steps of a relatively small size.

public float initTime;
public ParticleEmitter partEmitter;
// Use this for initialization
public float deltaTime = 0.1f;
void Start () {
    for (float i = 0.0f; i < initTime; i += deltaTime) {
        partEmitter.Simulate(deltaTime);
    }
}

I have taken your 0.1f here (a tenth of a second), but this might have to be even somewhat lower.

注意:

ParticleSystem.Simulate 的第1個引數,傳入的是DeltaTime。