2019-11-08

粒子光环

作业要求:

本次作业基本要求是三选一,选择第三个:
参考http://i-remember.fr/en 这类网站,使用粒子流编程制作一些效果,如“粒子光环”
参考师兄博客

实现效果

实现过程

新建对象

新建空对象ParticleHalo,给particleHalo新建两个空对象,并添加Particle System组件

代码

新建

新建ParticleData类,用来实现粒子效果

1
2
3
4
5
6
7
8
9
10
public class ParticleData
{
public float radius, angle, time;
public ParticleData(float radius_,float angle_,float time_)
{
radius = radius_; //半径
angle = angle_; //角度
time = time_; //开始运动的时间
}
}

再定义一个粒子系统的变量,存储对应数据

1
2
3
private ParticleSystem particleSys;
private ParticleSystem.Particle[] particleArray;
private ParticleData[] particleData;

公有成员可以在界面上直接调控

1
2
3
4
5
6
7
public int count = 10000;       // 粒子数量  
public float size = 0.03f; // 粒子大小
public float minRadius = 6.0f; // 最小半径
public float maxRadius = 10.0f; // 最大半径
public bool clockwise = true; // 顺时针|逆时针
public float speed = 2f; // 速度
public float pingPong = 0.02f; // 游离范围

初始化

Start函数进行初始化,主要是对粒子系统进行实例化,相当于在界面里调整各种属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private void Start()
{

particleArray = new ParticleSystem.Particle[count];
particleData = new ParticleData[count];

particleSys = this.GetComponent<ParticleSystem>();
particleSys.startSpeed = 0;
particleSys.startSize = size;
particleSys.loop = false;
particleSys.maxParticles = count;
particleSys.Emit(count);
particleSys.GetParticles(particleArray);

setParticlePosition();
}
//初始化粒子位置;
void setParticlePosition()
{
float midRadius, minRate, maxRate, radius,angle,theta,time;

for (int i = 0; i < count; i++)
{
midRadius = (maxRadius + minRadius) / 2;
minRate = Random.Range(1.0f, midRadius / minRadius);
maxRate = Random.Range(midRadius / maxRadius, 1.0f);
radius = Random.Range(minRadius * minRate, maxRadius * maxRate);
angle = Random.Range(0.0f, 360.0f);
theta = angle / 180 * Mathf.PI;
time = Random.Range(0.0f, 360.0f);

particleData[i] = new ParticleData(radius,angle,time);
//particleArray[i].position = new Vector3(particleData[i].radius * Mathf.Cos(theta), 0f, particleData[i].radius * Mathf.Sin(theta));
particleArray[i].position = new Vector3(particleData[i].radius * Mathf.Cos(theta), particleData[i].radius * Mathf.Sin(theta),0f);
}
particleSys.SetParticles(particleArray, particleArray.Length);
}

运动

让每个粒子的角度在每一帧都减少或增加一个值就可以实现旋转,价格速度差分层数让不同层的粒子旋转的速度不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private int diff = 10;  // 师兄博客说是速度差分层数  
private void Update()
{
float theta;
for (int i = 0; i < count; i++)
{
if (clockwise)
{
particleData[i].angle -= (i % diff + 1) * (speed / particleData[i].radius / diff);
}
else
{
particleData[i].angle += (i % diff + 1) * (speed / particleData[i].radius / diff);
}
// 保证angle在到360度,这个方法有点技巧。
particleData[i].angle = (360.0f + particleData[i].angle) % 360.0f;
theta = particleData[i].angle / 180 * Mathf.PI;
particleArray[i].position = new Vector3(particleData[i].radius * Mathf.Cos(theta), particleData[i].radius * Mathf.Sin(theta), 0f);
}
particleSys.SetParticles(particleArray, particleArray.Length);
}

设置粒子的跳动效果,让其在这个半径的附近进行“浮游”。主要是运用PingPong算法:
Update函数中在确定particleArr [i]的位置之前,对运动半径进行处理:

1
2
particleData[i].time += Time.deltaTime;
particleData[i].radius += Mathf.PingPong(particleData[i].time / minRadius / maxRadius, pingPong) - pingPong / 2.0f;

透明度和颜色

加入新的公有成员:

1
public Gradient colorGradient;

在inspector窗口里改变colorGradient的值

start函数进行颜色初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
void changeColor()
{
float colorValue;
for (int i = 0; i < count; i++)
{
//改变颜色
colorValue = (Time.realtimeSinceStartup - Mathf.Floor(Time.realtimeSinceStartup));
colorValue += particleData[i].angle/360;
while (colorValue > 1)
colorValue--;
particleArray[i].color = colorGradient.Evaluate(colorValue);
}
}

在Update函数的for循环里加上执行改变函数的语句

1
2
//Update
changeColor();

修改transform属性

项目地址

Github

演示视频

bilibili