最近看到一个网站,感觉里面的特效不错http://i-remember.fr/en
所以我尝试制作一下里面的粒子光环,鼠标悬停中间的按钮就会粒子收缩,移开就会扩散,先上效果图如下:
下面讲讲思路:首先肯定要用到粒子系统,怎么让它们呈圆环状分布呢?可以用三角函数来解决,对于一个特定的圆心和半径,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 initializationvoid 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 framevoid 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;}}}