Unity3D学习——粒子光环
来源:互联网 发布:同在一起网络剧 编辑:程序博客网 时间:2024/05/18 13:28
这次使用粒子系统模仿I Remember网站上面的光环效果
网站静态图
我实现的效果图
粒子系统设置
添加粒子系统到一个空对象下,并且给空对象挂上文末的脚本,设置粒子参数
注意:别忘了把该粒子系统拖到红线框中
设计思路
观察效果发现光环由两层顺时针转动的环组成
如下图,黑色圆环层粒子分布比较疏松范围广,红色圆环层密集而且有两个对称的缺口,并且红色顺时针转动速度较快
对于每个圆环,设置最大和最小半径,然后利用随机函数使粒子集中分布在中间半径处
对于粒子的具体位置,我们只需要得到它的实际半径以及圆心角即可转换成对应的(x, y, 0)坐标
- 如何使粒子集中在圆环中间区域
如上图,要让粒子尽可能集中在蓝线附近,
①随机生成一个半径max到达黄区
②随机生成一个半径min在绿色区域内
③随机在(min, max)范围内生成新的半径randomRadius,这样randomRadius就会在中间蓝线附近
代码如下:
//maxR是最大半径,minR是最小半径 float midRadius = (maxR + minR) / 2; float min = Random.Range(minR, midRadius); float max = Random.Range(midRadius, maxR); float randomRadius = Random.Range(min, max);
- 如何形成对称的缺口
因为粒子在两个对称方向分布稀疏,相反我们令它们在另两个方 向分布比较密集即可形成同样效果
方法和上面的相似,也是利用三次随机函数
例如,我令粒子在初始状态,密集的分布在0度和180度处
for (int i = 0; i < particleNum; i++){ ... //在(-90,90)范围内生成集中在0度附近的的角度 float minAngle = Random.Range(-90f, 0.0f); float maxAngle = Random.Range(0.0f, 90f); float angle = Random.Range(minAngle, maxAngle); //一半粒子向0度集中、令一半向180度集中 randomAngle = i % 2 == 0 ? angle : angle - 180; ... }
解决了上面两个主要问题后,再说一下粒子的存储、转动和缩放
- 粒子存储
为了管理粒子数据,新建粒子数据类,然后为其声明一个数组与粒子数组匹配
//创建粒子系统 public ParticleSystem particleSystem; //粒子数组 private ParticleSystem.Particle[] particlesArray; //粒子属性数组 private particleClass[] particleAttr; public class particleClass { public float radiu = 0.0f;//初始化半径 public float collect_radiu = 0.0f;//集合后的半径 public float temp_radiu = 0.0f;//粒子扩大缩放过程中的暂存半径 public float angle = 0.0f; public particleClass(float radiu_, float angle_, float collect_) { radiu = radiu_; angle = angle_; collect_radiu = collect_; temp_radiu = radiu_; } }
利用一个粒子数组存放了宽环和窄环的所有粒子,试过比例后发现把5/12粒子分配给宽环,剩下的7/12给窄环会比较好看,所以在分配粒子属性时也会先判断是哪个环的粒子再做不同的设置。
- 粒子转动
在Update函数中根据不同环的速率改变粒子角度后,根据原来半径和新角度重新分布位置即可
局部代码如下:
for (int i = 0; i < particleNum; i++) { //窄环快、宽环粒子移动速度慢 if (i > particleNum * 5 / 12) speed = 0.1f; else speed = 0.05f; //改变粒子角度后即可实现粒子顺时针移动 particleAttr[i].angle -= speed; particleAttr[i].angle = particleAttr[i].angle % 360; float rad = particleAttr[i].angle / 180 * Mathf.PI; …… //重新设置粒子位置 particlesArray[i].position = new Vector3(particleAttr[i].now_radiu * Mathf.Cos(rad), particleAttr[i].now_radiu * Mathf.Sin(rad), 0f);
粒子缩放
- 需要收缩时
如果粒子当前半径比平均半径大(外围粒子),则以一定的速度向预先算好的收缩后的半径缩小;反之(内围)则向预先算好的收缩半径扩大 - 需要扩张恢复时
则把当前半径与初始半径作比较,移动和上面收缩类似
为了看起来与网站效果接近一些,我令收缩时外环快、内环慢,扩张时外环慢、内环快。
局部代码如下:
- 需要收缩时
//判断需不需要缩放,改变粒子的暂存半径 if(flag == 0)//需要向中间收缩 { if (particleAttr[i].now_radiu > particleAttr[i].collect_radiu) { //两层环的收缩速度不同 if(i < particleNum * 5 / 12) particleAttr[i].now_radiu -= 3.0f * Time.deltaTime; else particleAttr[i].now_radiu -= 4.0f * Time.deltaTime; } else if(particleAttr[i].now_radiu < particleAttr[i].collect_radiu) { if (i < particleNum * 5 / 12) particleAttr[i].now_radiu += 2.0f * Time.deltaTime; else particleAttr[i].now_radiu += Time.deltaTime; } } else if(flag == 1)//扩大 { if (particleAttr[i].now_radiu < particleAttr[i].ini_radiu) { if (i < particleNum * 5 / 12) particleAttr[i].now_radiu += 2.0f * Time.deltaTime; else particleAttr[i].now_radiu += 3.0f * Time.deltaTime; } else if (particleAttr[i].now_radiu > particleAttr[i].ini_radiu) { if (i < particleNum * 5 / 12) particleAttr[i].now_radiu -= 4.0f * Time.deltaTime; else particleAttr[i].now_radiu -= 4.0f * Time.deltaTime; } }
完整代码
using UnityEngine;using System.Collections;public class ParticleRing: MonoBehaviour{ public class particleClass { public float ini_radiu = 0.0f;//初始化半径 public float collect_radiu = 0.0f;//集合后的半径 public float now_radiu = 0.0f;//粒子当前时刻半径,用于扩大缩小时与上两者比较 public float angle = 0.0f; public particleClass(float radiu_, float angle_, float collect_) { ini_radiu = radiu_; angle = angle_; collect_radiu = collect_; now_radiu = radiu_; } } //创建粒子系统, public ParticleSystem particleSystem; //粒子数组 private ParticleSystem.Particle[] particlesArray; //粒子属性数组 private particleClass[] particleAttr; public int particleNum = 12000; //较宽的环的内外半径 public float outMinRadius = 5.0f; public float outMaxRadius = 10.0f; //较窄的环(带缺口)的内外半径 public float inMinRadius = 6.0f; public float inMaxRadius = 9.0f; public float speed = 0.1f; public int flag; void Start() { flag = -1; particleAttr = new particleClass[particleNum]; particlesArray = new ParticleSystem.Particle[particleNum]; particleSystem.maxParticles = particleNum; particleSystem.Emit(particleNum); particleSystem.GetParticles(particlesArray); for (int i = 0; i < particleNum; i++) { //相应初始化操作,为每个粒子设置半径,角度 float randomAngle; // 随机产生每个粒子距离中心的半径,同时粒子要集中在平均半径附近 float maxR, minR; if(i < particleNum * 5 / 12)//这部分粒子属于较宽的那个环 { maxR = outMaxRadius; minR = outMinRadius; randomAngle = Random.Range(0.0f, 360.0f); } else//窄环带缺口,设置一半向0度集中、一半向180度集中,以便在90度和-90度形成两个对称缺口 { maxR = inMaxRadius; minR = inMinRadius; float minAngle = Random.Range(-90f, 0.0f); float maxAngle = Random.Range(0.0f, 90f); float angle = Random.Range(minAngle, maxAngle); randomAngle = i % 2 == 0 ? angle : angle - 180;//利用对称性设置另一半粒子 } float midRadius = (maxR + minR) / 2; float min = Random.Range(minR, midRadius); float max = Random.Range(midRadius, maxR); float randomRadius = Random.Range(min, max); float collectRadius; //注意设置平均半径外围的粒子缩小时移动的距离少一些 if (randomRadius > midRadius) collectRadius = randomRadius - (randomRadius - midRadius) / 2; else collectRadius = randomRadius - (randomRadius - midRadius) * 3 / 4; //粒子属性设置 particleAttr[i] = new particleClass(randomRadius, randomAngle, collectRadius); particlesArray[i].position = new Vector3(randomRadius * Mathf.Cos(randomAngle), randomRadius * Mathf.Sin(randomAngle), 0.0f); } //设置粒子 particleSystem.SetParticles(particlesArray, particleNum); } void Update() { for (int i = 0; i < particleNum; i++) { //根据新的角度 if (i > particleNum * 5 / 12) speed = 0.1f; else speed = 0.05f; particleAttr[i].angle -= speed; particleAttr[i].angle = particleAttr[i].angle % 360; float rad = particleAttr[i].angle / 180 * Mathf.PI; //判断需不需要缩放,改变粒子的暂存半径 if(flag == 0)//需要向中间收缩 { if (particleAttr[i].now_radiu > particleAttr[i].collect_radiu) { //两层环的收缩速度不同 if(i < particleNum * 5 / 12) particleAttr[i].now_radiu -= 3.0f * Time.deltaTime; else particleAttr[i].now_radiu -= 4.0f * Time.deltaTime; } else if(particleAttr[i].now_radiu < particleAttr[i].collect_radiu) { if (i < particleNum * 5 / 12) particleAttr[i].now_radiu += 2.0f * Time.deltaTime; else particleAttr[i].now_radiu += Time.deltaTime; } } else if(flag == 1)//扩大 { if (particleAttr[i].now_radiu < particleAttr[i].ini_radiu) { if (i < particleNum * 5 / 12) particleAttr[i].now_radiu += 2.0f * Time.deltaTime; else particleAttr[i].now_radiu += 3.0f * Time.deltaTime; } else if (particleAttr[i].now_radiu > particleAttr[i].ini_radiu) { if (i < particleNum * 5 / 12) particleAttr[i].now_radiu -= 4.0f * Time.deltaTime; else particleAttr[i].now_radiu -= 4.0f * Time.deltaTime; } } //粒子新的位置 particlesArray[i].position = new Vector3(particleAttr[i].now_radiu * Mathf.Cos(rad), particleAttr[i].now_radiu * Mathf.Sin(rad), 0f); } particleSystem.SetParticles(particlesArray, particleNum); } void OnGUI() { if (GUI.Button(new Rect(0, 10, 100, 30), "扩大/缩小")) { flag = (flag == -1)? 0: 1 - flag; } }}
0 0
- Unity3D学习——粒子光环
- Unity3D学习笔记(9)—— 粒子光环
- Unity3D学习(12)之粒子光环
- Unity3D学习:制作粒子光环特效
- ## Unity3D实现粒子光环效果
- Unity3d-制作粒子光环特效
- unity作业——关于粒子光环的设计
- Unity3D——粒子系统
- Unity3D学习(8)——粒子效果的实现
- 【Unity 3D游戏开发学习笔记】粒子光环
- Unity3D学习记录1——粒子效果受WindZone影响
- Unity3D粒子系统——实现粒子播放完成之后自动销毁
- Unity3D笔记第九天——粒子系统
- Unity3D学习笔记——组件之Effects(效果/特效)——Particle System(粒子系统)
- 银色光环——ASMX部署
- Unity3D shader 人物被选中光环/技能范围光环
- 学习OpenCV——粒子滤波
- unity学习笔记—一部分粒子系统
- 记录配置Hadoop+zookeeper+Hbase的完整过程(四)
- 解决TabLayout不能同时滚动与平均分配
- 【Unity】【Code】通用代码库(一)——物体的wasd移动
- 用 Python 统计高频字数
- 算法课第十周作业 | Minimum Path Sum
- Unity3D学习——粒子光环
- 递归的函数(SDUT2176)
- (一)最流行的网络请求框架Rxjava2+Retrofit完美封装
- java多线程学习
- 浅析Hadoop启动脚本
- 如何解决MySQL Visual Studio Cannot create a design window for the selected object
- [Vue.js启航]——数据的双向绑定
- VS如何连接Mysql
- 解决重复提交表单