Unity幸運(yùn)轉(zhuǎn)盤(pán)實(shí)戰(zhàn)項(xiàng)目
幸運(yùn)轉(zhuǎn)盤(pán)主要是由兩部分組成——轉(zhuǎn)盤(pán)、指針,實(shí)現(xiàn)的方式也分兩種,轉(zhuǎn)盤(pán)動(dòng)或者指針動(dòng),不過(guò)兩者的原理都是一樣的,這里就以指針動(dòng)做了一個(gè)項(xiàng)目級(jí)的demo(由于后面的圓盤(pán)中間的那條豎線有點(diǎn)往左偏,所以導(dǎo)致那些圣誕老人的顯示有些偏移)。< Demo 下載 >
在項(xiàng)目開(kāi)發(fā)中,一般這個(gè)功能的實(shí)現(xiàn)過(guò)程是:
1、當(dāng)點(diǎn)擊開(kāi)始的時(shí)候,轉(zhuǎn)盤(pán)開(kāi)始動(dòng), 同時(shí)向服務(wù)端發(fā)送協(xié)議;
2、服務(wù)端返回?cái)?shù)據(jù)(前端計(jì)算好對(duì)應(yīng)的角度),當(dāng)轉(zhuǎn)盤(pán)旋轉(zhuǎn)一定時(shí)間后開(kāi)始減速直至對(duì)應(yīng)角度
當(dāng)然也可以等服務(wù)端返回?cái)?shù)據(jù)后再開(kāi)始模擬旋轉(zhuǎn)過(guò)程,但是由于受網(wǎng)絡(luò)的影響,這一過(guò)程可能會(huì)較長(zhǎng),表現(xiàn)效果不是很好。
關(guān)于Unity的旋轉(zhuǎn),主要有下面幾類(lèi)接口:Transform.Rotate(), Transform.RotateAround(),Transform.rotation, Transform.eulerAngles。 其中 Rotate() 和 RotateAround() 都是同一類(lèi)接口(里面的具體重載這里就不細(xì)說(shuō)了),都是指從當(dāng)前位置做指定角度的偏移,而 rotation 和 eulerAngles 都是直接賦值的字段,rotation 是一個(gè)四元數(shù)類(lèi)型, eulerAngles 則是一個(gè)歐拉角。很顯然,我們?cè)谧鲂D(zhuǎn)的時(shí)候不需要關(guān)心具體角度,使用 Rotate() 類(lèi)型做定幀偏移是最合適的,通過(guò)設(shè)置偏移的角度就能實(shí)現(xiàn)變速轉(zhuǎn)動(dòng),比較適合轉(zhuǎn)盤(pán)開(kāi)始階段的加速過(guò)程和中間的勻速過(guò)程,而當(dāng)我們知道停止的具體角度時(shí),則可已利用差值運(yùn)算能精準(zhǔn)地實(shí)現(xiàn)減速過(guò)程并最終停到我們需要的位置。但是有一點(diǎn)需要注意,Unity里面角度是逆時(shí)針計(jì)算的,而我們?nèi)粘I钪幸话懔?xí)慣于順時(shí)針,所以,最終的角度還需要取反一下。廢話不多說(shuō),見(jiàn)代碼:
using UnityEngine; using UnityEngine.UI; public class LuckyTurntable : MonoBehaviour { public enum State { None, //待機(jī)狀態(tài) Start, //加速階段 Prepared, //等待數(shù)據(jù)階段 End, //減速階段 } public delegate void OnFinishCallback(); private event OnFinishCallback OnFinish; /// <summary> /// 設(shè)置完成時(shí)的回調(diào) /// </summary> /// <param name="onFinish"></param> public void SetOnFinishCallback(OnFinishCallback onFinish) { OnFinish += onFinish; } /// <summary> /// 最大速度 /// </summary> public int velocity = 3000; public Transform node; public Button btnStart; public Button btnStop; public Button btnRandom; public InputField input; private State _state; /// <summary> /// 轉(zhuǎn)盤(pán)的狀態(tài) /// </summary> public State CurState { get { return _state; } private set { _state = value; switch (value) { //不同階段限制各按鈕的點(diǎn)擊狀態(tài) case State.None: btnStart.enabled = true; btnStop.enabled = false; btnRandom.enabled = false; break; case State.Start: btnStart.enabled = false; btnStop.enabled = true; btnRandom.enabled = true; break; case State.Prepared: case State.End: btnStart.enabled = false; btnStop.enabled = false; btnRandom.enabled = false; break; } } } private float _endAngle = 0f; /// <summary> /// 最終停止的角度[0, 360] /// </summary> public float EndAngle { get { return _endAngle; } set { _endAngle = Mathf.Abs(value); print("End Angle: " + value); _endAngle = _endAngle % 360; //將角度限定在[0, 360]這個(gè)區(qū)間 _endAngle = -_endAngle - 360 * 2; //多N圈并取反,圈數(shù)能使減速階段變得更長(zhǎng),顯示更自然,逼真 } } /// <summary> /// 加速持續(xù)時(shí)間 /// </summary> private readonly float AcceleateTime = 1f; /// <summary> /// 減速前的最短持續(xù)時(shí)間 /// </summary> private float _minTime = 3.0f; /// <summary> /// 角度緩存 /// </summary> private float _tmpAngle = 0f; /// <summary> /// 時(shí)間統(tǒng)計(jì) /// </summary> private float _time; /// <summary> /// 速度變化因子 /// </summary> private float _factor; private void Start() { CurState = State.None; btnStart.onClick.AddListener(OnStartClick); btnStop.onClick.AddListener(OnStopClick); btnRandom.onClick.AddListener(OnRandomClick); } private void Update() { if (CurState == State.None) return; _time += Time.deltaTime; if (CurState == State.End) { //通過(guò)差值運(yùn)算實(shí)現(xiàn)精準(zhǔn)地旋轉(zhuǎn)到指定角度(球型插值無(wú)法實(shí)現(xiàn)大于360°的計(jì)算) float k = 2f; //如果嫌減速太慢,可以加個(gè)系數(shù)修正一下 _tmpAngle = Mathf.Lerp(_tmpAngle, EndAngle, Time.deltaTime * k); //這里只存在一個(gè)方向的旋轉(zhuǎn),所以不存在歐拉角萬(wàn)向節(jié)的問(wèn)題,所以使用歐拉角和四元數(shù)直接賦值都是可以的 node.rotation = Quaternion.Euler(0, 0, _tmpAngle); //node.eulerAngles = new Vector3(0, 0, _tmpAngle); if (1 >= Mathf.Abs(_tmpAngle - EndAngle)) { CurState = State.None; if (null != OnFinish) { OnFinish(); OnFinish = null; } } } else { //利用一個(gè)速度因子實(shí)現(xiàn)變加速的過(guò)程 _factor = _time / AcceleateTime; _factor = _factor > 1 ? 1 : _factor; node.Rotate(Vector3.back, _factor * velocity * Time.deltaTime, Space.Self); } //當(dāng)收到數(shù)據(jù)之后并且旋轉(zhuǎn)了一定時(shí)間后開(kāi)始減速 if (CurState == State.Prepared && _time > _minTime) { CurState = State.End; _tmpAngle = GetCurClockwiseAngle(); } } /// <summary> /// 將當(dāng)前指針的歐拉角轉(zhuǎn)換成順時(shí)針統(tǒng)計(jì)角度 /// </summary> /// <returns></returns> private float GetCurClockwiseAngle() { //由于讀取到的值是[0, 180] U [-180, 0],左邊由0至180遞增,右邊由180轉(zhuǎn)變成-180,然后遞增至0,所以需要轉(zhuǎn)相應(yīng)的轉(zhuǎn)換 return (-1) * (360 - node.eulerAngles.z) % 360; } private void OnStartClick() { CurState = State.Start; _time = 0; } /// <summary> /// 讀取輸入框中的角度并停止 /// </summary> private void OnStopClick() { try { EndAngle = float.Parse(input.text); } catch { EndAngle = 0f; } CurState = State.Prepared; } /// <summary> /// 隨機(jī)一個(gè)角度并停止 /// </summary> private void OnRandomClick() { EndAngle = UnityEngine.Random.Range(0f, 360f); CurState = State.Prepared; } }
功能代碼基本都在上面了,如果想要Demo的話可 前往下載 。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#檢查指定對(duì)象是否存在于ArrayList集合中的方法
這篇文章主要介紹了C#檢查指定對(duì)象是否存在于ArrayList集合中的方法,涉及C#中Contains方法的使用技巧,需要的朋友可以參考下2015-04-04C#跨平臺(tái)開(kāi)發(fā)之使用C/C++生成的動(dòng)態(tài)鏈接庫(kù)
這篇文章介紹了C#跨平臺(tái)開(kāi)發(fā)之使用C/C++生成的動(dòng)態(tài)鏈接庫(kù),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-01-01