所以我尝试制作一下里面的粒子光环,鼠标悬停中间的按钮就会粒子收缩,移开就会扩散,先上效果图如下:
下面讲讲思路:首先肯定要用到粒子系统,怎么让它们呈圆环状分布呢?可以用三角函数来解决,对于一个特定的圆心和半径,r*sin(弧度)就是该粒子的y轴坐标,r*cos(弧度)为x轴坐标,z轴就置零。因为这是一个环,有最小半径和最大半径,因此r要在这之间取随机数,而角度就360内都行(最后要转换成弧度制)。然后在里面的特效中的粒子应该是有顺时针也有逆时针的,这个我用奇偶数来实现,偶数顺时针,奇数逆时针~
附上我的粒子系统参数:
这时候的效果是这样的:
这样的粒子分布太均匀了,我们需要调整一下粒子的半径的概率。
我的方法有点复杂,因为最小半径跟最大半径不能改变,但是r的随机范围又不能在最大和最小之间均分(中间最多),这时候我可以增大中间半径的概率。
我先让r 的随机下界在最小半径到中间半径之间均匀随机,上界在中间半径和最大半径之间均匀随机,这样子的话,粒子在中间半径的概率就是其他位置的两倍了。
如图:
这样的效果就跟网站上的差不多了:
接下来就是鼠标悬停中间后粒子收缩的效果,鼠标悬停的判断呢,我是用光线射击到中间物体的方法。
收缩的实现就是先得出收缩后的粒子位置以及记录好收缩前的粒子位置。(在代码中有实现以及解释)
完成后就大功告成了~
最后附上代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class init : MonoBehaviour {
public ParticleSystem particleSystem;
public Camera ca;
private ParticleSystem.Particle[] particleRing;
private int particleNum = 10000;
private float radius = 5.0f;
private float maxRadius = 10.0f;
private float[] particleAngle;
private float[] particleR; //各个粒子的半径
private int level = 5;
private float speed = 0.1f;
private float[] circleR; //收缩前粒子位置
private float[] collectR; //收缩后粒子位置
private bool ischange = false; //是否收缩
private float collectSpeed = 2f;
// Use this for initialization
void Start () {
particleAngle= new float[particleNum]; //存储各个粒子的角度
particleR = new float[particleNum];
circleR = new float[particleNum];
collectR = new float[particleNum];
particleRing = new ParticleSystem.Particle[particleNum]; //代表各个粒子
particleSystem.maxParticles = particleNum; //粒子总数目
particleSystem.Emit(particleNum);
particleSystem.GetParticles(particleRing);
for (int i = 0; i < particleNum; i++) //初始化粒子位置
{
float midR = (maxRadius + radius) / 2; //中间半径
float temp1 = Random.Range(radius, midR); //下界
float temp2 = Random.Range(midR, maxRadius); //上界
float r = Random.Range(temp1, temp2); //最终粒子半径
float angle = Random.Range(0.0f, 360.0f);
particleAngle[i] = angle;
particleR[i] = r;
//得出收缩后的粒子位置以及记录好收缩前的粒子位置
circleR[i] = r;
collectR[i] = r - 1.5f * (r / radius);
if(collectR[i]<radius+0.5f)
{
float midRadius = radius + 0.25f;
float temp = Random.Range(radius, midRadius); //随机下界,防止收缩后成了原线而不是小圆环
collectR[i] = Random.Range(temp, (radius + 0.5f));
}
}
}
// Update is called once per frame
void Update () {
for (int i = 0; i < particleNum; i++)
{
if (ischange)
{
if(particleR[i]>collectR[i])
{
particleR[i] -= collectSpeed * (particleR[i] / collectR[i]) * Time.deltaTime;
}
} else
{
if(particleR[i]<circleR[i])
{
particleR[i] += collectSpeed * (circleR[i] / particleR[i]) * Time.deltaTime;
} else if(particleR[i] > circleR[i])
{
particleR[i] = circleR[i];
}
}
if (i % 2 == 0) //分为5个级别的粒子速度
{
particleAngle[i] += (i % level + 1) * speed;
}
else
{
particleAngle[i] -= (i % level + 1) * speed;
}
particleAngle[i] = particleAngle[i] % 360;
float rad = particleAngle[i] / 180 * Mathf.PI;
particleRing[i].position = new Vector3(particleR[i] * Mathf.Cos(rad), particleR[i] * Mathf.Sin(rad), 0f);
}
particleSystem.SetParticles(particleRing, particleNum);
Ray ray = ca.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit) && hit.collider.gameObject.tag == "button")
{
ischange = true;
} else
{
ischange = false;
}
}
}