前段時(shí)間整理的一篇關(guān)于unity ui開(kāi)發(fā)的文章朗和,被推薦上了csdn首頁(yè),對(duì)于剛剛寫(xiě)文字的我來(lái)說(shuō)按灶,是莫大的鼓勵(lì),讓我干勁十足筐咧,寫(xiě)出更多有質(zhì)量的文字鸯旁。
寫(xiě)在前面
屏幕適配是每個(gè)手機(jī)應(yīng)用和游戲都會(huì)解決的問(wèn)題,當(dāng)然在開(kāi)發(fā)的過(guò)程中會(huì)遇到各種各樣的坑,這次羡亩,我們就來(lái)討論一下unity項(xiàng)目中的屏幕適配吧摩疑!
目錄
- 屏幕適配的分類
- 哪些內(nèi)容需要適配
- unity中常見(jiàn)的適配方式
- 游戲內(nèi)容適配
- NGUI的適配方案
- UGUI的適配方案
屏幕適配的分類
說(shuō)到屏幕適配的分類啊,也許會(huì)有所疑問(wèn)畏铆,屏幕適配還能分類雷袋?細(xì)致分析一下,可以分為兩大類:分辨率適配和寬高比適配辞居。
分辨率適配
首先得知道分辨率是什么楷怒?分辨率是屏幕顯示圖像的緊密度,是指顯示器能顯示的像素有多少瓦灶。屏幕上的點(diǎn)鸠删、線、面都是由像素組成的贼陶,分辨率越高刃泡,同樣大小的屏幕能顯示的像素越多,畫(huà)面就越精細(xì)〉镎現(xiàn)在PC上分辨率大多是 1920 * 1080烘贴,我們看的視頻很多高清版本就是 1080p 的。
既然分辨率是屏幕的一項(xiàng)指標(biāo)撮胧,那么手機(jī)上當(dāng)然也會(huì)用到桨踪,現(xiàn)在智能手機(jī)市場(chǎng)有那么多產(chǎn)品,有多個(gè)廠家生產(chǎn)芹啥,并且有多個(gè)價(jià)位锻离,所以手機(jī)屏幕分辨率肯定各不相同(雖然屏幕分辨率一般比較固定的幾個(gè))。那么分辨率適配是每個(gè)應(yīng)用墓怀、游戲都應(yīng)該做的汽纠。寬高比適配
這個(gè)很好理解,每個(gè)手機(jī)大小各不相同捺疼,寬高比也會(huì)有多種啦疏虫,適配寬高比當(dāng)然也是必須要做的嘍。
當(dāng)下移動(dòng)設(shè)備主流分辨率及寬高比:
iOS設(shè)備的分辨率主要有:
Android設(shè)備的分辨率則相對(duì)紛雜啤呼,主流的分辨率有:
哪些內(nèi)容需要適配
- User Interface
游戲UI需要適配卧秘,這是無(wú)所質(zhì)疑的,包括一般的手機(jī)應(yīng)用程序官扣,都需要這個(gè)步驟翅敌。如果再細(xì)分一下,還分為位置適配和大小適配
位置適配:分辨率會(huì)影響UI在屏幕中顯示的位置惕蹄,比如在800 * 600分辨率的屏幕上蚯涮,button1在正中央位置治专,坐標(biāo)為(400, 300)遭顶,但是如果放在1366 * 768分辨率屏幕上位置就會(huì)靠左邊一些张峰,這樣會(huì)嚴(yán)重影響UI布局的美觀。
大小適配:同樣的例子棒旗,在800 * 600分辨率的屏幕上喘批,button1的大小為50*20像素,但是到了分辨率高的屏幕上铣揉,button1就變得很小了饶深,影響美觀,影響用戶正常使用逛拱。
- 游戲內(nèi)容
一般的應(yīng)用開(kāi)發(fā)敌厘,用戶看到的只有UI,但在游戲中朽合,除了UI俱两,還有游戲內(nèi)容。而游戲內(nèi)容是什么呢曹步?
舉個(gè)例子:
比如在2D游戲中锋华,除了那些可以交互的按鈕滾動(dòng),在二維場(chǎng)景中的背景箭窜、物件、NPC等衍腥,都屬于游戲內(nèi)容磺樱。在進(jìn)行寬高比適配的時(shí)候,難免會(huì)按照寬度或高度做一些裁剪婆咸,如果不進(jìn)行處理竹捉,有些游戲內(nèi)容就會(huì)看不到。
在3D游戲中尚骄,場(chǎng)景的大小是固定的块差,當(dāng)相機(jī)照射的寬高比因?yàn)檫m配屏幕寬高比變化時(shí),就可能“穿幫”倔丈,很有可能看到黑邊憨闰。
在unity中不管2D游戲還是3D游戲,分辨率大小不會(huì)影響游戲內(nèi)容顯示需五,屏幕寬高比會(huì)影響游戲內(nèi)容顯示鹉动。
注意:在unity編輯器中,game視圖是默認(rèn)的視口宏邮,并且編輯器下改變游戲?qū)捀弑仍笫荆瑄nity會(huì)自動(dòng)把相機(jī)寬高比調(diào)整到適配的寬高比缸血。
unity中常見(jiàn)的適配方式
- Camera組件
Projection:投影類型
Prespective為透視投影
Field of View:相機(jī)的張角,它決定相機(jī)照射的范圍械筛。
Clipping Planes:近裁剪面和遠(yuǎn)裁剪面
Viewport Rect:視口大小捎泻,取值為0 ~ 1之間
Orthographic為平行投影
與透視投影不同的是size屬性,它用來(lái)調(diào)整攝像機(jī)的大小
orthographicSize:等于相機(jī)高度的一半
注意一下埋哟,unity中的單位和像素之間有一個(gè)轉(zhuǎn)換關(guān)系笆豁,叫做Pixels To Units
默認(rèn)為100,unity中一個(gè)單位表示圖片的100個(gè)像素定欧。如果游戲屏幕高為800像素渔呵,那么換算后高度為 800 / 100 / 2 = 4。
unity沒(méi)有直接設(shè)置攝像機(jī)寬度的屬性砍鸠,也沒(méi)有獲取攝像機(jī)寬度的接口扩氢,但可以通過(guò)高度和寬高比計(jì)算出來(lái)。那么計(jì)算寬度如下:
cameraWidth = camera.orthographicSize * 2 * camera.aspect
換算成像素:cameraWidth * 100
cameraHeight = camera.orthographicSize * 2
換算成像素:cameraHeight * 100
相機(jī)的寬高比是unity自動(dòng)設(shè)置為當(dāng)前屏幕寬高比的爷辱,所以camera.aspect不需要自己設(shè)置录豺。
-
縮放
在Transform組件上,可以設(shè)置控制物體每個(gè)方向上的縮放比例饭弓。
錨點(diǎn)(相對(duì)位置)
目前NGUI双饥,UGUI都有類似的功能,稍后再討論弟断。
游戲內(nèi)容適配
游戲內(nèi)容可以分為兩類
有效內(nèi)容:游戲中一定需要顯示在屏幕上的內(nèi)容
實(shí)際內(nèi)容:包括有效內(nèi)容和為了適配咏花、或其它目的增加的內(nèi)容。
3D游戲中把要么場(chǎng)景做得比正常顯示時(shí)更大一些阀趴;要么顯示天空盒子昏翰。
2D游戲中也是把背景做得大一些,盡可能讓游戲不出現(xiàn)黑邊刘急。
我們的開(kāi)發(fā)一般都會(huì)選擇在一個(gè)固定的設(shè)計(jì)分辨率上進(jìn)行棚菊,比如常用的iOS豎屏游戲設(shè)計(jì)分辨率640*960,我們就以這個(gè)設(shè)計(jì)分辨率為例叔汁。通常情況下统求,設(shè)計(jì)分辨率尺寸就是我們游戲有效內(nèi)容的尺寸。
orthographicSize設(shè)置為4.8据块,就可以讓游戲內(nèi)容鋪滿屏幕
這里有一篇文章码邻,里面詳細(xì)講了unity 2D游戲的屏幕適配。
NGUI適配方案
-
UIRoot
NGUI中每一個(gè)UI都是以UIRoot作為根節(jié)點(diǎn)另假,該組件完成了NGUI大體上的適配功能冒滩。
UIRoot的幾種縮放方式:
Flexible:
在該模式下,下面的UI都是以像素為基礎(chǔ)浪谴,100像素的物體無(wú)論在多少分辨率上都是100像素开睡,這就意味著因苹,100像素在分辨率低的屏幕上可能顯示正常,但是在高分辨率上就會(huì)顯得很小篇恒。
在該模式下扶檐,UIRoot的屬性如下:
Minimum Height:設(shè)置為725時(shí),當(dāng)屏幕高度小于725時(shí)胁艰,在該屏幕上顯示的樣子和開(kāi)發(fā)時(shí)一致款筑。
Maximum Height:設(shè)置為1024時(shí),當(dāng)屏幕高度大于1024時(shí)腾么,在該屏幕上顯示的樣子和開(kāi)發(fā)時(shí)一致奈梳。
Shrink Portrait UI:當(dāng)是豎屏狀態(tài)時(shí),按寬度來(lái)適配解虱。
Adjust by DPI:使用dpi做適配計(jì)算攘须。
補(bǔ)充一下一些關(guān)于屏幕的基本概念
dip:設(shè)備無(wú)關(guān)像素
dp:就是dip
px:像素
dpi:像素密度,單位面積上有多少個(gè)像素點(diǎn)
分辨率:寬高兩個(gè)方向上的像素點(diǎn)數(shù)殴泰,如800*600
屏幕尺寸:屏幕對(duì)角線長(zhǎng)度
屏幕比例:寬高比
詳細(xì)的轉(zhuǎn)換關(guān)系于宙,去這里看看。
開(kāi)發(fā)時(shí)的布局:
改變Game視圖大泻费础:
改變Game視圖大小捞魁,高度大于725,小于1024离咐,(按剛剛的截圖中設(shè)置的值測(cè)試的):
在高度在Minimum和Maximum之間時(shí)谱俭,UIRoot就不會(huì)對(duì)下面的UI縮放了,開(kāi)發(fā)時(shí)有多少像素在高分辨下也只有那么點(diǎn)像素宵蛀,所以看起來(lái)就變小了旺上。
這個(gè)Minimum和Maximum Height用于你對(duì)實(shí)際的屏幕尺寸進(jìn)行限制,如果實(shí)際的屏幕尺寸小于Minimum糖埋,那么就相當(dāng)于設(shè)置了“Constrained”模式、Manual Height值設(shè)為Minimum的時(shí)候一樣窃这,同理瞳别,如果屏幕尺寸超過(guò)了Maximum,那也相當(dāng)于設(shè)置了“Constrained”模式杭攻、Manual Height值設(shè)為Maximum的時(shí)候一樣祟敛。
以上是在Flexible模式的關(guān)于分辨率的適配,還有一個(gè)是寬高比適配兆解,分兩種情況:
當(dāng)高大于寬的是馆铁,也就是豎屏狀態(tài)時(shí)
兩邊被截了
只需要勾上Shrink Portrait UI,就能按照寬度來(lái)適配了(因?yàn)槟J(rèn)橫屏狀態(tài)锅睛,并且默認(rèn)按高度適配埠巨,所以在看這段源碼的時(shí)候历谍,它里面的計(jì)算是寬高顛倒的):
當(dāng)寬大于高時(shí),也就是橫屏狀態(tài)時(shí):就需要自己來(lái)根據(jù)寬度來(lái)調(diào)整縮放辣垒。
- 動(dòng)態(tài)的改變適配的高度
public class NewBehaviourScript : MonoBehaviour {
public int ManualWidth = 1280;
public int ManualHeight = 720;
void Awake () {
UIRoot uiRoot = gameObject.GetComponent<UIRoot>();
if (uiRoot != null)
{
if (System.Convert.ToSingle(Screen.height) / Screen.width > System.Convert.ToSingle(ManualHeight) / ManualWidth)
uiRoot.minimumHeight = Mathf.RoundToInt(System.Convert.ToSingle(ManualWidth) / Screen.width * Screen.height);
else
uiRoot.minimumHeight = ManualHeight;
}
}
}
-
利用相機(jī)的camera.orthographicSize
需要知道orthographicSize表示的是相機(jī)高度的一半望侈,前面已經(jīng)講清楚了。我在16 : 9屏幕下開(kāi)發(fā)勋桶,并且設(shè)置camera.orthographicSize為1脱衙,把Minimum和Maximum設(shè)置為相同
,然后把下面腳本掛在UI相機(jī)上:
public class NewBehaviourScript : MonoBehaviour {
void Awake ()
{
camera.orthographicSize *= 16.0f / 9 / ((float)Screen.width / Screen.height);
}
}
16:9屏幕上正常:
不加上述腳本例驹,在5:4屏幕上捐韩,兩邊被裁剪了:
加上上述腳本,在5:4屏幕上就正常了鹃锈,按照寬度適配:
Constrained:
該模式下荤胁,屏幕按照尺寸比例來(lái)適配,不管實(shí)際屏幕有多大仪召,NGUI都會(huì)通過(guò)合適的縮放來(lái)適配屏幕寨蹋。這樣在高分辨率上顯示的UI就會(huì)被放大,有可能會(huì)模糊扔茅。
Content Width:按照該寬度值適配屏幕
Content Height:按照該高度值適配屏幕
Fit選項(xiàng)表示已哪個(gè)值做適配已旧。這兩個(gè)值可以認(rèn)為是事先設(shè)定好的屏幕初始大小和比例。源碼中Fit選項(xiàng)的枚舉值:
public enum Constraint
{
Fit,
Fill,
FitWidth,
FitHeight,
}
如果Fit都沒(méi)勾選(Constraint.Fill)
當(dāng)適配寬高比小于實(shí)際寬高比時(shí)召娜,就會(huì)按照寬度適配运褪,反之按照高度適配。該情況下可以保證顯示結(jié)果永遠(yuǎn)沒(méi)有黑邊玖瘸,但上下或者左右兩邊可能會(huì)被裁剪秸讹。如果勾選了Width(Constraint.FitWidth)
那么就會(huì)在屏幕比例發(fā)生變化時(shí),按照寬度來(lái)適配雅倒。例如開(kāi)發(fā)時(shí)用16:9屏幕璃诀,運(yùn)行在5:4屏幕上,寬度適配蔑匣,計(jì)算公式為 activeHeight = manualWidth / (screen.x / screen.y)劣欢,16 / ( 5 / 4 ) = 12.8 > 9,這樣顯示寬度就全部顯示進(jìn)來(lái)了裁良,但是高度上就會(huì)出現(xiàn)黑邊凿将,所以這種情況下要想辦法解決黑邊問(wèn)題。如果勾選了Height(Constraint.FitHeight)
那么就會(huì)在屏幕比例發(fā)生變化時(shí)价脾,按照寬度來(lái)適配牧抵。activeWidth = manualHeight * (screen.x / screen.y),9 * ( 5 / 4 ) = 11.25 < 16侨把,這樣高度全部顯示進(jìn)來(lái)犀变,但在寬度上兩邊被裁剪掉了妹孙,顯然這樣更不合適了。如果兩個(gè)都勾選了(Constraint.Fit)
當(dāng)適配寬高比大于實(shí)際寬高比時(shí)弛作,就會(huì)按照寬度適配涕蜂,反之按照高度適配。該情況下可以保證顯示開(kāi)發(fā)時(shí)能見(jiàn)到的所有內(nèi)容映琳,但是可能上下或左右會(huì)出現(xiàn)黑邊机隙。
下面是UIRoot.cs源碼:
可以清楚的看到NGUI是怎么利用這些值進(jìn)行計(jì)算高度的。
Constrained On Mobiles
前兩種模式的組合萨西,在PC和Mac等桌面設(shè)備上用Flexible模式有鹿, 在移動(dòng)設(shè)備上Constrained模式。
- UIAnchor or UIStretch
作為NGUI中一個(gè)組件谎脯,但之前做的項(xiàng)目里面好像怎么用葱跋,可以把它看做對(duì)一個(gè)UI樹(shù)中的局部進(jìn)行控制。它們?cè)谔幚砑?xì)節(jié)上很相似源梭,都是先計(jì)算參照對(duì)象(這個(gè)參照對(duì)象由Insprector的Container指定娱俺,如果沒(méi)有選擇,就是Camera)的大小Rect废麻,然后根據(jù)參數(shù)UIAnchor(Side,relativeOffset,pixelOffset)荠卷,UIStretch(Style,relativeSize,initialSize,borderPadding)進(jìn)行調(diào)整,最后設(shè)置對(duì)應(yīng)的屬性烛愧,只不過(guò)UIAnchor設(shè)置的是transform.position油宜,UIStretch設(shè)置的是(width,height)或clipRange等。
UIAnchor組件的視圖:
Container:指定Anchor的參照點(diǎn)怜姿,如果沒(méi)有選擇慎冤,則以Camera的pixelRect的區(qū)域?yàn)閰⒄彰?。
Side:錨點(diǎn)位置沧卢,有八個(gè)位置可選蚁堤。
Relative Offset:相對(duì)于Camera,或Container的百分比偏移 但狭。
Pixel Offset:像素的偏移披诗。
UIStretch組件的視圖:
大致和UIAnchor差不多,Style屬性有些改動(dòng)如下
Horizontal:橫向拉伸熟空。
Vertical:縱向拉伸。
Both:雙向拉伸搞莺,但xy方向上的拉伸比例不同息罗。
BasedOnHeight:雙向拉伸,但xy方向上的拉伸比例相同才沧,且比例基于height迈喉。
FillKeepingRatio:雙向拉伸,但xy方向上的拉伸比例相同绍刮,比例基于較大者。
FitInternalKeepingRatio:雙向拉伸挨摸,但xy方向上的比例相同孩革,比例基于較小者。
具體的可以自己研究一下得运,但是不建議用這個(gè)兩貨膝蜈,折騰了一下感覺(jué)太麻煩,而且根本沒(méi)必要啊熔掺,因?yàn)閁IRoot已經(jīng)做了大部分的適配了饱搏,那些局部細(xì)節(jié)上的調(diào)整完全可以用UIRect所管理的Anchor來(lái)實(shí)現(xiàn),它不是單獨(dú)的組件置逻,比這兩簡(jiǎn)單多了推沸,下面就來(lái)聊聊它。
- UIRect的Anchor
首先得了解一些UIRect券坞,這里不詳細(xì)聊它鬓催,后面會(huì)整理一篇分析NGUI底層的文章,里面有詳細(xì)說(shuō)它恨锚。簡(jiǎn)單介紹一下宇驾,從NGUI控件的繼承結(jié)構(gòu)上,UIRect是所有weight和panel的基類眠冈,管理著rect和anchor飞苇,計(jì)算、生成蜗顽,是一個(gè)抽象類布卡。
拿UISprite舉例:
Type:三種類型,使用錨點(diǎn)雇盖、基本控制忿等、完全控制。
Execute:設(shè)置在什么時(shí)候執(zhí)行錨點(diǎn)適配崔挖。
Target:參考物體贸街。
Left、Right狸相、Bottom薛匪、Top:該控件上下左右邊。
比如脓鹃,你想某個(gè)按鈕在任何尺寸屏幕上都停留在屏幕上的左邊逸尖,可以如下:
16:9屏幕上
錨點(diǎn)設(shè)置如下:UISprite的左右邊界都參考target的左邊
然后5:4屏幕上,UISprite依然在屏幕的左邊了
當(dāng)然其它的weight都可以設(shè)置錨點(diǎn),可以這么說(shuō)娇跟,凡事繼承自UIRect的組件都可以使用該錨點(diǎn)岩齿。
UGUI適配方案
終于把NGUI適配說(shuō)完了,對(duì)于UGUI目前沒(méi)有深入了解苞俘,在場(chǎng)景視圖中可以拖拽錨點(diǎn)盹沈,設(shè)置錨點(diǎn)區(qū)域,感覺(jué)挺簡(jiǎn)單的吃谣,粗略做個(gè)筆記乞封。
- Canvas Scaler:畫(huà)布比例縮放,從整體上對(duì)UI進(jìn)行適配控制基协,和UIRoot有異曲同工之妙歌亲,很多參數(shù)名字不一樣,但意思一樣澜驮。
ConstantPixelSize:按像素適配
Constant Pixel Size:保持UI元素大小不變陷揪,無(wú)論屏幕尺寸如何變化,所占像素不變杂穷。
Scale Factor:保持大小的比例 悍缠。原圖100x100 原始大小1=100x100 原來(lái)的2倍大 2=200x200
Reference Pixels Per Unity: 100 Unity里的1單位大小代表100像素
ScaleWithScreenSize:按比例適配
Scale With Screen Size:UI元素大小跟隨屏幕分辨率的大小變化而變化。
Reference Resolution:參考分辨率耐量。
Screen Match Mode:
Match Width Or Height:根據(jù)參考分辨率的高或?qū)挿沈荆瑏?lái)縮放UI元素。
Expland:分辨率設(shè)置不會(huì)小于Canvas設(shè)置的分辨率廊蜒。
Shrink:分辨率不會(huì)大于Canvas設(shè)置的分辨率趴拧。
Constant Physical Size:按屏幕物理大小適配
根據(jù)屏幕的PPI信息和ConstantPhysicalSize本身的配置信息,得出一個(gè)“合適”的scaleFactor山叮,以達(dá)到UI在不同PPI設(shè)備上的最終大小都是一致的著榴。
- 錨點(diǎn)
UGUI中錨點(diǎn)有多種“形態(tài)”,當(dāng)錨點(diǎn)是一個(gè)點(diǎn)時(shí)屁倔,表示該UI大小不變脑又,位置會(huì)隨參考點(diǎn)改變。當(dāng)錨點(diǎn)是一個(gè)矩形區(qū)域時(shí)锐借,UI的大小就會(huì)隨該參考區(qū)域改變问麸,當(dāng)然非常靈活,錨點(diǎn)矩形的大小可以隨意設(shè)置钞翔,甚至可以在某個(gè)方向長(zhǎng)度為0严卖。
寫(xiě)在最后
以上就是屏幕適配的所有內(nèi)容,主要介紹了屏幕適配的分類:分辨率適配和寬高比適配布轿,按內(nèi)容又分為游戲UI適配和游戲內(nèi)容適配哮笆,并給出一些適配方法俺亮。然后重點(diǎn)講了NGUI的適配方法,簡(jiǎn)單介紹了UGUI疟呐,總的來(lái)說(shuō)UGUI和NGUI適配的方案有很多相似的地方,適配的大致方向就是按像素东且、按比例縮放對(duì)全局適配启具,用錨點(diǎn)來(lái)做精細(xì)的控制。對(duì)UGUI現(xiàn)在不是很熟珊泳,所以寫(xiě)的很簡(jiǎn)單鲁冯,以后找時(shí)間在詳細(xì)研究一下,再整理出來(lái)色查。