unity作業——關於粒子光環的設計

這次作業是讓我們做一個網站首頁的光環效果,網站如下:http://i-remember.fr/en 


        可以看出,粒子光環大約有兩層,外層粒子呈順時針旋轉,內層粒子呈逆時針旋轉,總的來說可以採用如下方式來設計,建立一個總的對象halo,

其中包含兩個子對象out和in,分別代表外層粒子和內層粒子。粒子的位置和運動採用極座標來控制,從數學上我們知道,與圓和旋轉相關的活動, 採用極座標較爲方便。最後使用pingpong函數,使粒子在半徑方向上游離即可。

下面是具體的設計過程,先創建一個空的halo對象,爲其添加out子對象,代表外層光環,對out子對象增加粒子系統、

新建一個c#腳本halo,這裏因爲代碼量較小,我們採用自上而下的設計方式,先在start和update函數中把需要的功能列好,再一步步實現該功能。

	void Start () {
		initial ();
		RandomOperation ();
	}
	void Update () {
		rotate ();
	}

這裏initial函數代表初始化粒子系統,RandomOpeartion函數使得粒子隨機分佈在圓軌道上,rotate函數使得粒子可以進行旋轉。

在實現每個函數之前,我們先來確定一下要聲明的變量,在這裏我引入一個新類,circlePosition,用來表示粒子的極座標,其屬性有半徑,角度和時間,代碼如下:

public class CirclePosition
{
	public float radius = 0f, angle = 0f, time = 0f;
	public CirclePosition(float ra, float an, float ti) {
		radius = ra;
		angle = an;
		time = ti;
	}
}

要聲明的變量如下:

	private ParticleSystem pSys; // 粒子系統
	private ParticleSystem.Particle[] pArr; // 粒子數組
	private CirclePosition[] cirPos; // 每個粒子的極座標
	private int count = 10000; // 粒子數量
	private float size = 0.1f;  // 粒子大小
	private float minRadius = 5.0f; // 運動最小半徑
	private float maxRadius = 12.0f;  // 運動最大半徑
	private float speed = 2f; // 運動速度
	private float pp = 0.02f; // 遊離範圍
	private int speedDiffer = 15; // 與遊離有關的分層變量

     接下來便是初始化粒子系統,initial函數的實現,該函數功能主要是爲兩個數組開闢空間,同時爲各個變量進行初始化:
    
public void initial() {
		cirPos = new CirclePosition[count];
		pArr = new ParticleSystem.Particle[count];
		pSys = this.GetComponent<ParticleSystem> ();
		pSys.loop = false;
		pSys.startSize = size;
		pSys.startSpeed = 0;
		pSys.maxParticles = count;
		pSys.Emit (count);
		pSys.GetParticles (pArr);
	}
然後是使得粒子隨機分佈在圓軌道上的函數RandomOperation

      注意這裏,我們想讓粒子更多集中的分佈在平均半徑附近,也就是我們上面聲明的最大半徑和最小半徑的均值,注意這裏我們使用的是弧度,產生角度時還要做一個數學上的代換
public void RandomOperation() {
		float midRadius;
		float minRate;
		float maxRate;
		float radius;
		float angle;
		float circleAngle;
		float time;
		for (int i = 0; i < count; i++) {
			midRadius = (maxRadius + minRadius) / 2;
			minRate = Random.Range (1.0f, midRadius / minRadius);
			maxRate = Random.Range (midRadius / maxRadius, 1.0f);
			radius = Random.Range (minRadius * minRate, maxRadius * maxRate);
		    angle = Random.Range (0.0f, 360.0f);
			circleAngle = angle / 180 * Mathf.PI;
			time = Random.Range (0.0f, 360.0f);
			cirPos [i] = new CirclePosition (radius, angle, time);
			pArr [i].position = new Vector3 (cirPos [i].radius * Mathf.Cos (circleAngle), 0f, cirPos [i].radius * Mathf.Sin (circleAngle)); 
		}
		pSys.SetParticles (pArr, pArr.Length);
	}
最後便是使得粒子旋轉的函數rotate

	speedDiffer是一個分層變量,目的是爲了使得粒子角度添加的增量不同,同時利用direction變量控制順時針和逆時針,這裏還要注意一點,隨機產生的角度必須要在0到360度
	最後那個pingpong函數是爲了使得粒子產生遊離效果,具體代碼如下:
	
public void rotate() {
		float circleAngle;
		for (int i = 0; i < count; i++) {
			if(direction)
			cirPos [i].angle -= (i % speedDiffer + 1) * (speed / cirPos [i].radius / speedDiffer);
			else 
			cirPos [i].angle += (i % speedDiffer + 1) * (speed / cirPos [i].radius / speedDiffer);
			cirPos [i].angle = (360.0f + cirPos [i].angle) % 360.0f;
			circleAngle = cirPos [i].angle / 180 * Mathf.PI;
			pArr [i].position = new Vector3 (cirPos [i].radius * Mathf.Cos (circleAngle), 0f, cirPos [i].radius * Mathf.Sin (circleAngle));
			cirPos [i].time += Time.deltaTime;
			cirPos [i].radius += Mathf.PingPong (cirPos [i].time / minRadius / maxRadius, pp) - pp / 2.0f;
		}
		pSys.SetParticles (pArr, pArr.Length);
	}


	到這裏基本上一個外層粒子就寫完了,內層粒子也就是將那個direction的鉤打掉,再略微改一下參數就行了
	這裏我稍微改了一下顏色,使得內外層粒子顏色各不相同,看的效果更加明顯。
	運行效果如下:
	 

	最後是此次的完整代碼
	
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CirclePosition
{
	public float radius = 0f, angle = 0f, time = 0f;
	public CirclePosition(float ra, float an, float ti) {
		radius = ra;
		angle = an;
		time = ti;
	}
}
public class halo : MonoBehaviour {
	private ParticleSystem pSys; // 粒子系統
	private ParticleSystem.Particle[] pArr; // 粒子數組
	private CirclePosition[] cirPos; // 每個粒子的極座標
	public bool direction = true;
	private int count = 10000; // 粒子數量
	private float size = 0.1f;  // 粒子大小
	private float minRadius = 5.0f; // 運動最小半徑
	private float maxRadius = 12.0f;  // 運動最大半徑
	private float speed = 2f; // 運動速度
	private float pp = 0.02f; // 遊離範圍
	private int speedDiffer = 15; // 與遊離有關的分層變量
	public void initial() {
		cirPos = new CirclePosition[count];
		pArr = new ParticleSystem.Particle[count];
		pSys = this.GetComponent<ParticleSystem> ();
		pSys.loop = false;
		pSys.startSize = size;
		pSys.startSpeed = 0;
		pSys.maxParticles = count;
		pSys.Emit (count);
		pSys.GetParticles (pArr);
	}
	public void RandomOperation() {
		float midRadius;
		float minRate;
		float maxRate;
		float radius;
		float angle;
		float circleAngle;
		float time;
		for (int i = 0; i < count; i++) {
			midRadius = (maxRadius + minRadius) / 2;
			minRate = Random.Range (1.0f, midRadius / minRadius);
			maxRate = Random.Range (midRadius / maxRadius, 1.0f);
			radius = Random.Range (minRadius * minRate, maxRadius * maxRate);
		    	angle = Random.Range (0.0f, 360.0f);
			circleAngle = angle / 180 * Mathf.PI;
			time = Random.Range (0.0f, 360.0f);
			cirPos [i] = new CirclePosition (radius, angle, time);
			pArr [i].position = new Vector3 (cirPos [i].radius * Mathf.Cos (circleAngle), 0f, cirPos [i].radius * Mathf.Sin (circleAngle)); 
		}
		pSys.SetParticles (pArr, pArr.Length);
	}
	public void rotate() {
		float circleAngle;
		for (int i = 0; i < count; i++) {
			if(direction) // 順時針
			cirPos [i].angle -= (i % speedDiffer + 1) * (speed / cirPos [i].radius / speedDiffer);
			else 	//逆時針
			cirPos [i].angle += (i % speedDiffer + 1) * (speed / cirPos [i].radius / speedDiffer);
			//確保範圍在0到360度
			cirPos [i].angle = (360.0f + cirPos [i].angle) % 360.0f;
			circleAngle = cirPos [i].angle / 180 * Mathf.PI;
			pArr [i].position = new Vector3 (cirPos [i].radius * Mathf.Cos (circleAngle), 0f, cirPos [i].radius * Mathf.Sin (circleAngle));
			//使得粒子游離
			cirPos [i].time += Time.deltaTime;
			cirPos [i].radius += Mathf.PingPong (cirPos [i].time / minRadius / maxRadius, pp) - pp / 2.0f;
		}
		pSys.SetParticles (pArr, pArr.Length);
	}
	void Start () {
		initial ();
		RandomOperation ();
	}
	void Update () {
		rotate ();
	}
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章