参考 http://i-remember.fr/en 这类网站,使用粒子流编程控制制作一些效果, 如“粒子光环”
粒子系统有许多大模块,比如最常用的有初始化模块、发射模块、粒子群形状模块,颜色随存活时间、速度变化的模块等。这里重点学习了一下最重要的初始化模块中各个参数的作用。
参数 | 功能 |
---|---|
持续时间(Duration) | 粒子系统发射粒子的持续时间 |
循环(Looping) | 粒子系统是否循环 |
预热(Prewarm) | 当looping开启时,才能启动预热(Prewarm),游戏开始时粒子已经发射了一个周期 |
初始延迟(Start Delay) | 粒子系统发射粒子之前的延迟。注意在prewarm(预热)启用下不能使用此项 |
初始生命(Start Lifetime) | 以秒为单位,粒子存活数量 |
初始速度(Start Speed) | 粒子发射时的速度 |
初始大小(Start Size) | 粒子发射时的大小 |
初始旋转(Start Rotation) | 粒子发射时的旋转值 |
初始颜色(Start Color) | 粒子发射时的颜色 |
重力修改器(Gravity Modifier) | 粒子在发射时受到的重力影响 |
继承速度(Inherit Velocity) | 控制粒子速率的因素将继承自粒子系统的移动(对于移动中的粒子系统) |
模拟空间(Simulation Space) | 粒子系统在自身坐标系还是世界坐标系 |
唤醒时播放(Play On Awake) | 如果启用粒子系统当在创建时,自动开始播放 |
最大粒子数(Max Particles) | 粒子发射的最大数量 |
对 http://i-remember.fr/en 上的例子进行了一定的学习后,最后打算做一些改进和创新,利用其原理实现一个卫星带,再用这个卫星带实现一个卫星带围绕行星转的效果。详细过程请见实现步骤。
this.transform.Rotate(Vector3.up * 30 * Time.deltaTime);
public class ParticleInfo
{
public float radius = 0;
public float angle = 0;
public ParticleInfo(float radius, float angle)
{
this.radius = radius; // 半径
this.angle = angle; // 角度
}
}
private ParticleSystem particleSys; // 粒子系统
private ParticleSystem.Particle[] particleArr; // 粒子数组
private ParticleInfo[] info; // 粒子信息数组
float speed = 0.25f; // 速度
public int count = 8000; // 粒子数量
void Start () {
// 初始化粒子数组
particleArr = new ParticleSystem.Particle[count];
info = new ParticleInfo[count];
// 初始化粒子系统
particleSys = this.GetComponent();
particleSys.loop = false; // 取消粒子循环
particleSys.startSpeed = 0; // 设置粒子初速度
particleSys.maxParticles = count; // 设置最大粒子量
particleSys.Emit(count); // 发射粒子
particleSys.GetParticles(particleArr);
IniAll(); // 初始化所有粒子
}
void IniAll()
{
for (int i = 0; i < count; ++i)
{
// 随机每个粒子半径,集中于平均半径附近
float midRadius = 8.0f;
float radius = Random.Range(midRadius - 2, midRadius + 2);
// 随机每个粒子的角度
float angle = Random.Range(0, 360);
// 转换成弧度制
float radian = angle / 180 * Mathf.PI;
// 随机每个粒子的大小
float size = Random.Range(0.01f, 0.03f);
info[i] = new ParticleInfo(radius, angle);
particleArr[i].position = new Vector3(info[i].radius * Mathf.Cos(radian), 0f, info[i].radius * Mathf.Sin(radian));
particleArr[i].size = size;
}
// 通过初始化好的粒子数组设置粒子系统
particleSys.SetParticles(particleArr, particleArr.Length);
}
void Update()
{
for (int i = 0; i < count; i++)
{
// 除以半径是为了使速度更加多样化
float rotateSpeed = (speed / info[i].radius) * (i % 10 + 1);
// 一半粒子顺时针转,一半粒子逆时针转
if (i % 2 == 0)
{
info[i].angle -= rotateSpeed;
}
else
{
info[i].angle += rotateSpeed;
}
// 保证角度合法
info[i].angle %= 360.0f;
// 转换成弧度制
float radian = info[i].angle * Mathf.PI / 180;
particleArr[i].position = new Vector3(info[i].radius * Mathf.Cos(radian), 0f, info[i].radius * Mathf.Sin(radian));
}
// 通过粒子数组设置粒子系统
particleSys.SetParticles(particleArr, particleArr.Length);
}
void IniAll()
{
float minRadius = 6.0f; // 最小半径
float maxRadius = 10.0f; // 最大半径
for (int i = 0; i < count; ++i)
{
// 随机每个粒子半径,集中于平均半径附近
float midRadius = (maxRadius + minRadius) / 2;
float minRate = Random.Range(1.0f, midRadius / minRadius);
float maxRate = Random.Range(midRadius / maxRadius, 1.0f);
float radius = Random.Range(minRadius * minRate, maxRadius * maxRate);
...
}
// 通过初始化好的粒子数组设置粒子系统
particleSys.SetParticles(particleArr, particleArr.Length);
}
改后效果:
- 优化,采用类似的原理,可以让每个粒子在一个很小的位置范围内抖动,让画面更加真实带感,实现方法是在update方法中可以加入一下随机的偏移量。
void Update()
{
for (int i = 0; i < count; i++)
{
...
// 粒子在半径方向上抖动
float offset = Random.Range(-0.01f, 0.01f); // 偏移范围
info[i].radius += offset;
particleArr[i].position = new Vector3(info[i].radius * Mathf.Cos(radian), 0f, info[i].radius * Mathf.Sin(radian));
}
// 通过粒子数组设置粒子系统
particleSys.SetParticles(particleArr, particleArr.Length);
}
到此便和一开始展示的效果完全一致了。