对于最新版的粒子系统Particle System,要让其跟随路径移动,无非就是借用其自身的API直接为每个粒子设置速度。
看一下最终的效果图:
编辑器
为了能在场景中更方便的编辑路径,我们要将路径点的编辑功能加入到Inspector界面,但同时我们并不想破坏ParticleSystem自身的Inspector界面,所以这需要在不替换掉ParticleSystem组件原有Editor扩展的情况下加入我们的扩展布局。
这里的思路来自于雨松MOMO的一篇文章:http://www.xuanyusong.com/archives/3931
方法十分简单粗暴,直接用反射获取ParticleSystemInspector类(这是Unity底层对于ParticleSystem组件的Inspector界面扩展类),创建一个实例,然后每次在我们自己的OnInspectorGUI()方法调用时,都调用一次ParticleSystemInspector实例的OnInspectorGUI()方法,也就是在ParticleSystem的Inspector界面同时保持了两种布局。
代码如下:
private Assembly _assembly;
private Type _particleSystemInspector;
private MethodInfo _onInspectorGUI;
private Editor _particleSystemEditor;
//载入程序集
_assembly = Assembly.GetAssembly(typeof(Editor));
//获取ParticleSystemInspector类
_particleSystemInspector = _assembly.GetTypes().Where(t => t.Name == "ParticleSystemInspector").FirstOrDefault();
//获取OnInspectorGUI方法
_onInspectorGUI = _particleSystemInspector.GetMethod("OnInspectorGUI", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
//创建ParticleSystemInspector的实例
_particleSystemEditor = CreateEditor(target, _particleSystemInspector);
然后在我们自己的Editor类的OnInspectorGUI()方法中,加一句话就可以了:
_onInspectorGUI.Invoke(_particleSystemEditor, null);
这样,再加上我们自己的布局代码,就可以在ParticleSystem的Inspector界面同时保持两种布局。
编辑路径
1.勾选路径模式前面的复选框,为开启路径模式,粒子系统的所有粒子都将忽略原有的生命值和速度,保证自身的生命值能够走到路径的结尾。
2.选中路径点,可以在场景中编辑路径点的位置。
3.右下角的加号为新增路径点。
4.Speed的值越小,粒子的移动速度越快。
代码实现
ParticleSystem的粒子类(Particle)有一个速度属性,包含了速度方向与速度值,我们只需要根据路径的变化改变其值就可以了:
//路径
public List<Vector3> Waypoints;
//获取当前的激活粒子
ParticleSystem.Particle[] ps = new ParticleSystem.Particle[PS.particleCount];
int pCount = PS.GetParticles(ps);
for (int i = 0; i < pCount; i++)
{
//计算生命值比例
float proportion = (ps[i].startLifetime - ps[i].remainingLifetime) / ps[i].startLifetime;
//判断所在的路径点
int index = Mathf.FloorToInt(proportion * Waypoints.Count);
if (index >= 0 && index < Waypoints.Count - 1)
{
Vector3 direction = Waypoints[index + 1] - Waypoints[index];
//赋予新的速度
ps[i].velocity = direction * (1.0f / Speed) * (1.0f / transform.localScale.x);
}
else
{
//超出路径之后,粒子销毁
ps[i].remainingLifetime = 0;
}
}
//重新设置粒子
PS.SetParticles(ps, pCount);