Unity 倒放粒子系统(循环倒放)
- 在电影信条中有关于物体倒放的特效,恰巧在制作一个独立游戏的时候,我们也用到了粒子特效的反向播放,在查阅一些资料后,最终使用了unity官方公众号给出的一个关于倒放粒子系统的方法。
- 官方表明,Unity本身不支持从初始偏移时间倒放粒子系统,粒子系统会无视所有设为负模拟值的属性,并将所有属性设为0。但在后面的方法中使用一个方法particleSystems.Simulate()去模拟给定的一个粒子系统的运行时刻。
- 缺点是,当你从很靠后的时间去模拟粒子倒放时,因为要多次调用particleSystems.Simulate(),而每次调用都要从0时刻模拟到你要的时刻,这就非常耗费性能,以至于模拟偏移量大的时刻时画面十分卡顿。
- 而本篇文章是在原官方给出的方法上加以改进了一下(没有循环效果),方法是将原本的一个粒子系统增加至两个,并给两个粒子系统一个初始的时间偏移(做法可以是一个赋值为循环周期,一个为循环周期的一半),以及一个循环的周期,粒子第一次播放是从初始时间偏移开始反向播放,在第一次播放完成后,偏移一个周期重新反向播放。
- 本方法和官方所给的有微小的区别,我修改后的方法如下,如果看不太懂的可以先看一下原文倒放粒子系统
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ParticleSystemReverseSimulationSuperSimple : MonoBehaviour
{
ParticleSystem particleSystems;
public float startTime = 2.0f;
public float simulationSpeedScale = 1.0f;
public float T;
bool flg;
void Initialize()
{
particleSystems = transform.GetComponent<ParticleSystem>();
}
void Update()
{
if (Input.GetMouseButtonDown(1))
{
flg = !flg;
if (!flg)
{
StartInverseParticalCoroutine();
}else
{
StopInverseParticalCoroutine();
}
}
}
void OnEnable()
{
if (particleSystems == null)
{
Initialize();
}
flg = true;
particleSystems.Play(true);
}
public void StopInverseParticalCoroutine()
{
StopCoroutine("InversePartical");
particleSystems.Play(true);
}
public void StartInverseParticalCoroutine()
{
particleSystems.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
StartCoroutine("InversePartical");
}
float currentSimulationTime;
IEnumerator InversePartical()
{
if (particleSystems == null)
{
Initialize();
}
currentSimulationTime = startTime;
while (true)
{
bool useAutoRandomSeed = particleSystems.useAutoRandomSeed;
particleSystems.useAutoRandomSeed = false;
particleSystems.Play(false);
float deltaTime = particleSystems.main.useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
currentSimulationTime -= (deltaTime * particleSystems.main.simulationSpeed) * simulationSpeedScale;
particleSystems.Simulate(currentSimulationTime, true, true, true);
particleSystems.useAutoRandomSeed = useAutoRandomSeed;
if (currentSimulationTime < 0)
{
currentSimulationTime = T;
}
yield return null;
}
}
}