实现如下图的粒子光环:
参考网站:http://i-remember.fr/en
思路:
首先声明定义一个类用于存储每个粒子的半径和角度
public class particleClass {
public float radius = 0.0f; // initialize
public float angle = 0.0f; // initialize
public particleClass(float radius_, float angle_)
{
radius = radius_;
angle = angle_;
}
}
定义声明一些需要用到的变量,如最大粒子数目,粒子的数组和存储粒子半径和角度类的数组,内环和外环的半径,粒子旋转的速度和分组,分组用于确定粒子顺时针或逆时针旋转。
public int maxParticlesNum = 6000; // the max number of particles
public ParticleSystem particleSystem;
private ParticleSystem.Particle[] particlesArray;
private particleClass[] paticleObject;
public float minRadius = 3.5f; // inner race radius
public float maxRadius = 10.0f; // outer race radius
public float speed = 0.23f; // the speed of particles
public int group = 2; // group 1 rotates clockwise and group 2
// rotates anticlockwise
Start函数内初始化两个数组的大小,并且获得粒子对象,然后进行遍历,对每个粒子的位置进行随机设置,但这里实际上需要使得粒子尽可能位于环的中心,也就是(maxRaidus+minRadius)/2的位置,下面是直接采用了1个算法。随后就存储每个粒子的位置信息和设置他的位置。
void Start() {
particlesArray = new ParticleSystem.Particle[maxParticlesNum];
paticleObject = new particleClass[maxParticlesNum];
particleSystem.maxParticles = maxParticlesNum;
particleSystem.Emit(maxParticlesNum);
particleSystem.GetParticles(particlesArray);
for (int i = 0; i < maxParticlesNum; i++) {
//random angle produced
float randomAngle = Random.Range(0.0f, 360.0f);
// random radius which is closed to the midRadius in a large probility produced
float midRadius = (maxRadius + minRadius) / 2;
// quote someone else's algorithm
float minRate = Random.Range(1.0f, midRadius / minRadius);
float maxRate = Random.Range(midRadius / maxRadius, 1.0f);
float randomRadius = Random.Range(minRadius * minRate, maxRadius * maxRate);
//set two arrays
// save a new particle's radius & angle
paticleObject[i] = new particleClass(randomRadius, randomAngle);
// confirm its position
particlesArray[i].position = new Vector3(randomRadius * Mathf.Cos(randomAngle), randomRadius * Mathf.Sin(randomAngle), 0.0f);
}
//set particle
particleSystem.SetParticles(particlesArray, maxParticlesNum);
}
Update函数中,采用奇数和偶数ID来分成两个组,并且按照i和group来更新他的速度(可以改其他表达式,做到每个粒子速度不会全部相同即可),然后要更新他的角度,因为角度有周期,可能超过360度,采用取余即可避免这个问题,再次更新粒子位置。
void Update() {
// run setting, devided in 2 group
for (int i = 0; i < maxParticlesNum; i++) {
if (i % 2 == 0) { // judge if this particle should be group 1
paticleObject[i].angle += (i % group + 1) * speed;
} else { // or group 2
paticleObject[i].angle -= (i % group + 1) * speed;
}
//set new position according to the new angle
paticleObject[i].angle = paticleObject[i].angle % 360;
float new_angle = paticleObject[i].angle / 180 * Mathf.PI;
particlesArray[i].position = new Vector3(paticleObject[i].radius * Mathf.Cos(new_angle), paticleObject[i].radius * Mathf.Sin(new_angle), 0f);
}
particleSystem.SetParticles(particlesArray, maxParticlesNum);
}
Inspector设置:
运行结果:
完整代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ParRotation : MonoBehaviour {
public class particleClass {
public float radius = 0.0f; // initialize
public float angle = 0.0f; // initialize
public particleClass(float radius_, float angle_)
{
radius = radius_;
angle = angle_;
}
}
public int maxParticlesNum = 6000; // the max number of particles
public ParticleSystem particleSystem;
private ParticleSystem.Particle[] particlesArray;
private particleClass[] paticleObject;
public float minRadius = 3.5f; // inner race radius
public float maxRadius = 10.0f; // outer race radius
public float speed = 0.23f; // the speed of particles
public int group = 2; // group 1 rotates clockwise and group 2 rotates anticlockwise
void Start() {
particlesArray = new ParticleSystem.Particle[maxParticlesNum];
paticleObject = new particleClass[maxParticlesNum];
particleSystem.maxParticles = maxParticlesNum;
particleSystem.Emit(maxParticlesNum);
particleSystem.GetParticles(particlesArray);
for (int i = 0; i < maxParticlesNum; i++) {
//random angle produced
float randomAngle = Random.Range(0.0f, 360.0f);
// random radius which is closed to the midRadius in a large probility produced
float midRadius = (maxRadius + minRadius) / 2;
// quote someone else's algorithm
float minRate = Random.Range(1.0f, midRadius / minRadius);
float maxRate = Random.Range(midRadius / maxRadius, 1.0f);
float randomRadius = Random.Range(minRadius * minRate, maxRadius * maxRate);
//set two arrays
// save a new particle's radius & angle
paticleObject[i] = new particleClass(randomRadius, randomAngle);
// confirm its position
particlesArray[i].position = new Vector3(randomRadius * Mathf.Cos(randomAngle), randomRadius * Mathf.Sin(randomAngle), 0.0f);
}
//set particle
particleSystem.SetParticles(particlesArray, maxParticlesNum);
}
void Update() {
// run setting, devided in 2 group
for (int i = 0; i < maxParticlesNum; i++) {
if (i % 2 == 0) { // judge if this particle should be group 1
paticleObject[i].angle += (i % group + 1) * speed;
} else { // or group 2
paticleObject[i].angle -= (i % group + 1) * speed;
}
//set new position according to the new angle
paticleObject[i].angle = paticleObject[i].angle % 360;
float new_angle = paticleObject[i].angle / 180 * Mathf.PI;
particlesArray[i].position = new Vector3(paticleObject[i].radius * Mathf.Cos(new_angle), paticleObject[i].radius * Mathf.Sin(new_angle), 0f);
}
particleSystem.SetParticles(particlesArray, maxParticlesNum);
}
}