【Unity】UGUI系列教程——OSU!Video!
前言
在前篇的OSU教程中已經簡單的完成了基礎戰鬥部分,缺失的轉動圓盤功能這裡會做補充。而且為了讓遊戲效果更好,我會在遊戲中插入視頻,並講解Unity5.6之後新出的VideoPlayer功能(一個很方便的視頻播放系統)。最後UI相關的知識點(網上收集整理的)補充遊戲啊,這樣各位對UGUI的知識就掌握的七七八八了。
廢話不多說先上效果圖:
圓盤轉動數學知識
圓盤轉動主要是對我么在圓盤上輸入的位置點和之前的位置點做處理,讓UI知道我們是往哪個方向轉動的。曾經入門Unity的時候沒有太多的經驗,使用的是以圓盤中心劃分四個象限,通關滑鼠的偏移來做的旋轉。現在來看,感嘆當初遊戲數學知識不過關,為了避免各位讀者也走我之前的老路,我先普及一個數學概念。
向量的點乘和叉乘
點乘:
兩個向量點乘得到一個標量 ,數值等於兩個向量長度相乘後再乘以二者夾角的餘弦值
公式裡面有個餘弦值,我們可以利用餘弦的特性判斷出:
若為 o,則表示兩個向量之間角度是垂直關係, 。
若小於0 ,則兩個向量夾角大於90°。
若結果 >0 ,則兩個向量夾角小於 90°
總結:點乘通常用來判斷角度,在判斷物體是否轉動到目標角度、虛擬搖桿在某個方向上的力度,或者shader裡面對光線做處理都會用到這個。
叉乘:
數學老師曾說過,兩個向量叉乘確定一個平面,而平面是有方向的。
a X b不等於b X a,因為確定的平面方向是剛好相反的,比如a X b我們根據右手定則,得到的是向上的向量,若b X a我們的右手就是向著a向量方向收攏,得到是向下的向量。
總結:叉乘通常判斷向量的方向,判斷a在b向量的相對位置通過叉乘的正負判斷是非常有效的。
代碼原型實現
我們只用獲取到滑鼠開始拖拽轉盤UI時,每次滑鼠偏移位置帶來的角度變化,以及轉盤左轉還是右轉,因為我們想讓轉動是單方向的,就直接轉動為逆時針的時候直接return,如果要任意轉動,則將return的地方改為angle=-angle。
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.EventSystems;public class TurnAround :NoteLogic{ /// <summary> /// UI上的圓盤物體 /// </summary> public RectTransform uiDisk; /// <summary> /// 對UI監聽的一個重寫(可以下載源碼查看) /// </summary> public EventTriggerListener eventTrigger; /// <summary> /// 上一幀點擊的方向 /// </summary> Vector2 perTouchDir; /// <summary> /// 圓盤中心點位置 /// </summary> Vector2 uiDiskPos; /// <summary> /// 當前轉動角度記錄 /// </summary> float curAngle; /// <summary> /// 和上篇一樣,通過重構虛函數,讓操作部分實現不同Node不同操作。 /// </summary> public override void OnJudgetOperation() { //將Ugui的開始拖拽事件和拖拽事件綁定功能函數 eventTrigger.onBeginDrag = BegionTurn; eventTrigger.onDrag = Turn; uiDiskPos = uiDisk.transform.position; //協程判斷時間是否超出,超出則直接判定當前分數 StartCoroutine(OnDelayCall(judgeTime)); } IEnumerator OnDelayCall(float rTime) { yield return new WaitForSeconds(rTime); JudgetStore(); } /// <summary> /// 開始拖拽UI的時候,儲存一個點擊點到轉盤中心點的向量 /// </summary> public void BegionTurn(PointerEventData rData) { perTouchDir = rData.position - uiDiskPos; } /// <summary> /// 轉動處理 /// </summary> /// <param name="rData"></param> public void Turn(PointerEventData rData) { //得到當前滑鼠到轉盤中心的向量 var curTouchDir = rData.position - uiDiskPos; //上一幀向量和當前幀向量叉乘得到一個判斷當前向量位置值 var crossValue = Vector3.Cross(perTouchDir, curTouchDir); //獲取兩幀之間轉動的角度(Unity自帶的函數,原理其實可以用點乘來搞定) float angle = -Vector3.Angle(perTouchDir, curTouchDir); //如果逆時針旋轉,不響應 if (crossValue.z > 0) { return; } //讓ui旋轉角度 uiDisk.transform.Rotate(new Vector3(0, 0, angle)); //保存當前幀向量 perTouchDir = curTouchDir; curAngle -= angle; //提示的圓圈UI根據轉動的值由大變小 circleTipObj.gameObject.transform.localScale = Vector3.one * Mathf.Lerp(10, 0, curAngle / targetValue); //轉動到目標值判定分數 if (curAngle > targetValue) { JudgetStore(); } } public void JudgetStore() { if (curState == eState.Over) { return; } if (curAngle > targetValue) { curScore = eScore.Perfect; } else if (curAngle > targetValue*0.6f) { curScore = eScore.Good; } else { curScore = eScore.Fail; } StopCoroutine("OnDelayCall"); SetCurState(eState.Over); }}
(繼承NoteLogic的代碼有改動,對項目感興趣的朋友可以下載源碼)
VideoPlayer視頻播放
說到視頻播放曾經是Unity的一個坑點,PC和手機平台的視頻播放採用兩種方式。電腦上是MovieTexture格式還得裝QuickTime,手機上則是利用Handheld.PlayFullScreenMovie介面播放而且還是直接停止代碼運行(怎麼做功能啊喂!)。項目中為了用到視頻最後採用了MobileMovieTexture插件,但是效果有點差,得用專門的格式,還得放在流文件夾,而且音效還得單獨製作。
但是之前5.6更新的時候,新出的VideoPlayer功能搞定了以上的問題,PC端和手機端播放視頻的方式都做了統一,而且支持攝像機鏡頭播放,UGUI播放等多種播放方式,同時還能直接搞定音頻。簡直太方便了!
先說流程:
1.放入視頻文件,這裡我將視頻轉換成了Unity支持的格式MP4
2.新建VideoPlayer組件,簡單介紹下組件的功能
Source:可以選擇是本地視頻還是URL視頻,如果是URL視頻只用下方寫上地址即可。
Wait For First Frame: 勾選PlayOnAwake後有效,避免載入視頻過程中直接播放卡掉前幾幀。
PlaybackSpeed:視頻播放速度。
RenderMode:視頻是哪裡方式渲染的,目前有再攝像機上渲染,渲染到貼圖上,渲染到材質球,和OnlyAPI(沒對這個介面做研究)
AspectRatio:長寬比,是寬度適配還是高度適配。
Audio OutPut Mode:音頻輸出方式,這裡選用通關AudioSource輸出。
3.因為我們將視頻渲染到UI上,因此需要一個目標渲染的貼圖,創建一個渲染貼圖
可以直接設置貼圖的像素:
4.創建一個UICanva當作視頻播放的界面
然後創建一個RawImage組件,掛載VideoPlayer組件,和音頻組件
RawImage的貼圖可以是任意類型,不一定是Sprite類型,因此我們沒有選用Image組件。
這樣我們就可以實現視頻播放了,是不是特別簡單?
順便補充:
VideoPlayer可以使用一系列事件來監聽播放的各個動作:
errorReceived: 錯誤監聽到時被執行
frameDropped :有丟幀發生時被執行
frameReady :新的一幀準備好時被執行
loopPointReached :播放結束或播放到循環的點時被執行
prepareCompleted :視頻準備完成時被執行
seekCompleted :查詢幀操作完成時被執行
started:在Play方法調用之後立刻調用
UGUI的相關知識點補充
以下是對UI相關的知識點整理,有自己闡述的也有來源於網路各處的,如果侵權聯繫我會進行刪除。
什麼是圖集?
在使用3D技術開發2D遊戲或製作UI時(即使用GPU繪製),都會使用到圖集 ,那麼什麼是圖集呢?準確的說法圖集是一張包含了多個小圖的大圖和一份記錄了每個小圖id、位置、尺寸等數據的數據文件 。
為什麼要用圖集?
在GPU已經成為PC、手機等設備的必備組件的現在,把所有顯示的繪製操作交給專門處理圖像的GPU顯然比交給CPU更合適,這樣空閑下來的CPU可以集中力量處理遊戲的邏輯運算。
而GPU處理圖像的做法和CPU是不一樣的,在GPU中,我們要繪製一個圖像需要提交圖片(即紋理)到顯存,然後在進行繪製(這個過程稱為一次DrawCall),那麼如果我們一幀要繪製100個就需要提交100次圖片,如果使用包含了這100圖片的圖集,只需要一次提交即可,即一次DrawCall就搞定,處理效率上會有很大的提升。
另外使用圖集也方便管理和歸類各個模塊的圖片,可以通過一次載入和一次卸載完成多個圖片的處理,同理,載入次數也下來了,可以提升運行效率。
CPU與GPU的限制
GPU一般具有填充率(Fillrate)和內存帶寬(Memory Bandwidth)的限制,如果你的遊戲在低質量表現的情況下會快很多,那麼,你很可能需要限制你在GPU的填充率。
CPU一般被所需要渲染物體的個數限制,CPU給GPU發送渲染物體命令叫做DrawCalls。一般來說DrawCalls數量是需要控制的,在能表現效果的前提下越少越好。通常來說,電腦平台上DrawCalls幾千個之內,移動平台上DrawCalls幾百個之內。這樣就差不多了。當然以上並不是絕對的,僅作一個參考。
如何使用圖集
在Unity中我們只要使用小圖片即可,可以通過設置圖片的Packing Tag來指定小圖會被打包到的圖集,比如2個小圖的Packing Tag都叫「MyAtlas」,則Unity會將這兩個小圖打包到名為「MyAtlas」的圖集中。
注意圖片不能放在Resources文件夾下面,Resources文件夾下的資源將不會被打入圖集。
通過設置我們就可以發現多個同一Packing Tag的小圖放到場景中只會消耗一個DrawCall,表示我們的圖集已經開始起作用了。
Unity用到的基本圖片格式
Unity3D引擎對紋理的處理是智能的:不論你放入的是PNG,PSD還是TGA,它們都會被自動轉換成Unity自己的Texture2D格式。
在Texture2D的設置選項中,你可以針對不同的平台,設置不同的壓縮格式,如IOS設置成PVRTC4,Android平台設置成RGBA16等。嗯,非常的智能。
tga是無損支持透明的無壓縮格式,dds有一點點壓縮,png是無損壓縮,對效率要求高的可以tga,dds,ui一般png,psd不可取
格式對比
2的n次方冪天然被GPU接受
為什麼要關心渲染順序?
1.如果是2D遊戲,渲染順序關係著每個層次的顯示先後,比如UI在遊戲內容前面,遊戲內容又有多層次。舉一個簡單的例子,在橫版2D遊戲中,經常會用到多層滾動的背景,把遊戲物體分層管理起來,可以有效的減少出錯幾率,很好的控制顯示效果。
2.對於3D遊戲,遊戲內容是3D的,UI一般是2D,有很多時候需要把某個模型啊,粒子特效啊,放在界面上,這樣就有一個問題,3D物體和2D界面的先後關係,比如有些界面是在模型之上的,有些在下面,嘗試過很多種辦法,都能實現需求,但不是每種辦法都是那麼舒服的。
unity中控制渲染順序的方式
Camera是unity中最優先的渲染順序控制。depth越大,渲染順序越靠後。
sortingLayer 和 sortingOrder
按照字面意思是層的排序,Canvas和Renderer都有這個屬性。
Canvas中的sorting layer可以控制Canvas的層級
Sorting order可以控制UI和粒子的層級
RenderQueue
這是unity中的一個概念,大致意思就是渲染順序 。
所以一般設置材質的renderQueue或直接在shader中設置。
(可以再Debug模式下直接修改)
在ShaderLab中,有4個提前定義好的render queue,你可以設置更多的在他們之間的值:
Background :表示渲染在任何物體之前
Geometry(default):渲染大多數幾何物體所用的render queue
AlphaTest:用於alpha測試
Transparent:用於渲染半透明物體
Overlay:渲染所有物體之上
空間深度
在攝像機坐標系下的Z軸,控制著該相機下的物體的深度,在fragment shader中進行深度測試,這樣就控制了渲染到屏幕的順序。
總結
轉盤轉動功能用數學方法可以很容易來解決,遊戲中用到數學的地方非常的多,附上一個關於遊戲中數學問題的答https://www.zhihu.com/question/64347261/answer/219551214。
關於視頻功能,Unity新出的VideoPlayer功能簡單易用,同時安全性也高。若舊版本的升級後,項目需要視頻功能的朋友可以試試這個功能。而且視頻相對使用2D動畫和即時演算雖然佔用包體大小,但是對實際內存佔用缺不高,對資源的依賴性也非常低。如果製作開場效果,選用視頻方法來實現是非常不錯的。
最後補充的UI相關知識,Unity在弱化圖集的概念,但是工程項目中圖集理解缺至關重要。同時渲染的知識也牽扯到UI,這個對自動化開關管理UI和修改粒子的層級效果至關重要。
最後附上源碼:
chs71371/OSU_Battle
(包里有視頻,我做了一個壓縮包,解壓就可以了,位置Resources/assetsbundles/video)
對遊戲開發感興趣的同學,歡迎圍觀我們:【皮皮關遊戲開發教育】 ,會定期更新各種教程乾貨,更有別具一格的線下小班教育。在你學習進步的路上,有皮皮關陪你!~
我們的官網地址:http://levelpp.com/
我們的遊戲開發技術交流群:610475807
我們的微信公眾號:皮皮關
推薦閱讀:
※《Battle Brothers》:傭兵隊的日常
※恐怖遊戲嚇人的規律有哪些?
※遊戲可以既休閑又重度嗎?《精靈寶可夢》在20年前就辦到了