作业要求
参考http://i-remember.fr/en 这类网站,使用粒子流编程控制制作一些效果, 如“粒子光环”
这个网站打不开,参考了一下师兄们的博客的图片:
我看了一下,我感觉和上课做的粒子海洋有一些相似,就是需要变成一个环形。
制作流程
粒子光环制作
- 添加一个空对象,并且添加部件ParticleSystem,然后简单设置一下属性:
再设置一下Render的属性中的材料。
粒子光环的属性
创建一个脚本ParticleCircle
public ParticleSystem myparticleSystem; //粒子系统
private ParticleSystem.Particle[] particleArray;
private SingleParticle[] points;
public Gradient grad;
int count = 1000;
public float size = 0.5f;
public float minRadius = 3.0f;
public float maxRadius = 6.0f;
public float speed = 0.5f; // 速度参数
- ParticleSystem.Particle[] particleArray
粒子数组,保存了每一个粒子的状态,同时规定一个数量count,也就是数组的大小。
- SingleParticle[] points
记录了每个粒子对于整个光环的状态,两个最重要的属性角度与半径,因为每个粒子都是绕中心点运动,所以运动轨迹会有一个半径,运动到什么地方就需要角度来记录。这里用到自己定义的一个类SingleParticle。
- Gradient grad
颜色渐变器
- 粒子大小,光环内径外径,转圈速度,旋转方向等。
粒子的位置属性
定义的一个类SingleParticle:通过角度和半径来估算粒子所在的xy平面的面积,xy坐标就是通过三角函数来计算出来。
public class SingleParticle {
public float angle;
public float radius;
private float x = 0.0f;
private float y = 0.0f;
public void CalPosition() {
float temp = angle / 180.0f * Mathf.PI;
y = radius * Mathf.Sin(temp);
x = radius * Mathf.Cos(temp);
}
public SingleParticle(float angle, float radius) {
this.angle = angle;
this.radius = radius;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
粒子系统初始化
- 初始化属性:
void Start () {
// myparticleSystem = this.GetComponent<ParticleSystem>();
particleArray = new ParticleSystem.Particle[count];
points = new SingleParticle[count];
var m = myparticleSystem.main;
m.startSpeed = 0;
m.startSize = size;
m.maxParticles = count;
myparticleSystem.Emit(count);
myparticleSystem.GetParticles(particleArray);
Init();
}
- init的函数就是作为粒子位置的初始化
通过内径和外径,中间划分一个分截,粒子分别在这两个部分中随机分布,角度则是360度随机。
private void Init() {
int i;
for (i = 0; i < count; i++) {
float midRadius = (minRadius + maxRadius) / 2.0f;
float minRate = Random.Range(1.0f, midRadius / minRadius);
float maxRate = Random.Range(midRadius / maxRadius, 1.0f);
float radius = Random.Range(minRadius * minRate, maxRadius * maxRate);
float angle = Random.Range(0.0f, 360.0f);
points[i] = new SingleParticle(angle, radius);
points[i].CalPosition();
particleArray[i].position = new Vector3(points[i].getX(), points[i].getY(), 0f);
}
myparticleSystem.SetParticles(particleArray, particleArray.Length);
}
- Update
每次更新都需要循环遍历1000个粒子,对于每个粒子的状态都做一次改变,像角度颜色等
- 将1000个粒子分为10层,每一层转动的角度(即速度)都略微不一样,然后分成3部分:第一、三部分是同一个方向旋转,第二部分是另一个方向旋转。最后需要对增加后的角度取模,以免溢出360度,或者小于0度。最后算出xy坐标。
- 颜色的改变,通过代码来选择其中的颜色,随时间变化,用Gradient渐变器的Evaluate获取对应的颜色,SetParticles函数将这些计算出来的颜色和位置设置到粒子本身中去。
void Update () {
int i;
int level = 10;
for (i = 0; i < count; i++) {
if (i % level < 3 || i % level > 6)
{
points[i].angle -= rotate_speed * (i % level + 1) * speed;
} else {
points[i].angle += rotate_speed * (i % level + 1) * speed;
}
points[i].angle = (points[i].angle + 360.0f) % 360.0f;
points[i].CalPosition();
float value = Time.realtimeSinceStartup % 1.0f;
value -= rotate_speed * points [i].angle /360.0f;
while (value > 1)
value--;
while (value < 0)
value ++;
particleArray[i].startColor = grad.Evaluate(value);
particleArray[i].position = new Vector3(points[i].getX(), points[i].getY(), 0.0f);
}
myparticleSystem.SetParticles(particleArray, particleArray.Length);
}
改进——制作缩放
- 增加变量
public bool rotate_way = false; // 决定圈扩大还是缩小
private float rotate_speed = -1; // 颜色旋转速度(正负代表方向)
private float time = 0;
- 修改update函数
总时长为10,然后分成两段,一段是放大,一段是缩小的
time += Time.deltaTime;
if (time < 10) {
if (time < 5) {
rotate_way = false;
rotate_speed += 0.01f;
}
else {
rotate_way = true;
rotate_speed -= 0.01f;
}
} else {
time = 0;
rotate_speed = -1;
}
在对粒子属性的循环中,加入以下代码:
将粒子分成两部分(还是熟悉的配方,不知道为什么这么执迷于分层),然后一部分圈半径改变的速度快一点,一部分改变得慢一点,注意不能差别太大,可能会分层。
if (i % level > 5) {
float tmp = rotate_way? 1 : -1;
points[i].radius += tmp * 0.05f;
}
if (i % level <= 5) {
float tmp = rotate_way? 1 : -1;
points[i].radius += tmp * 0.052f;
}
增加——轨迹
选择一个材料:
游戏效果
是一个自动放大缩小、三层粒子以不同速度和方向运动且带有轨迹的粒子光环。
(这里是静态图,不太会搞动图)
后记
这一次的代码比较容易,需要注意的是分层单独设置的部分,要做出那种类似粒子海洋的涌动那种感觉。