【unity】NGUI之UIRoot屏幕分辨率自適應

http://blog.csdn.net/onerain88/article/details/11713299android

NGUI在Unity3D遊戲開發中很是經常使用,而NGUI對於每個UI場景,都是以一個UIRoot爲UI遊戲對象樹的根的,那麼這個UIRoot是起什麼做用的呢?ios

先簡單看一下UIRoot中的基本屬性算法

UIRoot遊戲對象的屬性只有4個,分別是縮放規則,手動高度,最小高度和最大高度iphone

而正是這4個屬性,將影響整個UI場景中總體的縮放比例,當設置好這4個屬性以後,UIRoot遊戲對象的相對縮放值(LocalScale)將會生成而且不能被直接修改(NGUI中不少屬性都是不能直接被修改的,這種控制是在UIRoot腳本中,經過設置[ExecuteInEditMode]作到的,其相對縮放值是根據UIRoot的4個屬性計算出來的),那麼這4個屬性分別是什麼含義呢?ide

(吐槽一下,也許這裏的用戶體驗並不足夠友好,由於Manual Height和Minimum Height, Maximum Height並不會同時起做用,若是能作到在選擇Scaling Style時動態的切換,使用者也許能更清楚它們之間的關係)學習


1.Scaling Style (縮放類型)

這是一個簡單的枚舉變量,包括三個枚舉值ui

[csharp] view plaincopyprint?spa

  1. public enum Scaling  .net

  2.     {  設計

  3.         PixelPerfect,  

  4.         FixedSize,  

  5.         FixedSizeOnMobiles,  

  6.     }  

public enum Scaling
	{
		PixelPerfect,
		FixedSize,
		FixedSizeOnMobiles,
	}

(FixedSize和FixedSizeOnMobiles相似,而且後者只添加了對ios和android平臺的判斷,因此前者能夠替代後者使用)

 

這裏只討論PixelPerfect和FixedSize的區別,二者都是針對於全部在此UIRoot之下的UI組件而言的,也能夠認爲是在此UIRoot下,整個遊戲屏幕的尺寸的縮放類型!


2.Manual Height和Minimum Height, Maximum Height (手動高度和最小高度,最大高度)

Manual Height和Minimum Height, Maximum Height不會同時對此UIRoot起做用,當選擇Scaling Style爲PixelPerfect時,咱們須要設置Minimum Height, Maximum Height;而當Scaling Style爲FixedSize或FixedSizeOnMobiles時,咱們須要設置Manual Height。(這就是我前面吐槽的緣由)


3.使用

(1)PexelPerfect和Minimum Height, Maximum Height

這個組合主要用於咱們指望全部的UI紋理都「儘可能」不進行縮放,所謂「儘可能」的程度,則是取決於Minimum Height和Maximum Height,Minimum Height表示當設備分別率小於此設置值時,根據此設置值對UIRoot進行縮放;Maximum Height表示當設備分辨率大於此設置值時,根據此設置值對UIRoot進行縮放(UIRoot是UI遊戲對象樹的根,修改UIRoot的縮放,則會影響整棵UI樹的縮放)

(2)FixedSize和Manul Height

這個組合主要用於咱們指望全部的UI紋理都進行「合適」的縮放,所謂「合適」縮放的原則,則是根據Manual Height設置值,當設備分辨率的高度值不一樣於此設置值時,則根據其比例(即Manual Height / Screen Height)對整棵UI樹的進行「等比」縮放(寬度的縮放比也是此比例值),這樣,咱們就能夠作一套資源,在不一樣尺寸的分辨率最好的「不變形」的適配了

(3)交集

前面兩組在什麼狀況下等同呢?

Manual Height == Minimum Height == Maximum Height 

推導過程,呵呵~~

具體可參考UIRoot中activeHeight屬性和GetPixelSizeAdjustment的計算過程


4.這也許並不夠

基於以上推到,當咱們以1024x768爲標準分辨率作一套UI資源(也就是選擇FixedSize而且Manual Height=768),彷佛能夠知足百分之90以上的機型了,而爲何是1024x768呢?

既然咱們已經容忍在除1024x768以外的其餘設備上進行等比縮放了,那爲何不是960x640呢?

計算一下1024x768的寬高比=1.33,960x640的寬高比=1.5,這就是移動設備的分辨率比例的所有了嗎?

固然不是,iphone5的比例就要大於1.5,還有各類奇葩的android設備呢,好比夏新的n828就是960x540,寬高比=1.78

那爲何以1024x768爲標準呢?

由於1.33的寬高比,當咱們的1024x768的資源到960x640的設備上時會有什麼現象?

根據Manual Height / Screen Height的比例可知,咱們須要縮放768 / 640 = 1.2倍,假設是一張1024x768的紋理,高度縮放1.2倍變爲了640,寬度也要相應縮放1.2倍變爲853(保證等比縮放不變形),也就是說1024x768的資源放到960x640上反而兩邊有了黑邊,這是咱們能夠容忍的,咱們能夠作一個很大的背景或者拉伸,保證UI組件不變形便可,不少遊戲都是這麼作的,好比植物大戰殭屍在iphone5和ipad上看到的背景視野並不同大!

當放到夏新的機器上呢?

咱們須要縮放768 / 540 = 1.4倍,寬度1024 / 1.4 = 731,這是能夠的,只是看起來更怪一些,由於兩邊的黑邊相對比例更大了(960 - 731=229的黑邊區域)

而我表示android機器的分辨率奇葩到只有想不到,沒有作不到的程度,也許寬高比1.7並非終點,當遇到1.8以後,黑邊的相對比例會更大。。。


5.問題又來了

假設咱們的遊戲類型更適合iphone手機玩,不太適合ipad,因此我但願能以960x640爲標準作一套資源,能夠嗎?

我只能說不太能夠,由於你要在設計UI組件的大小作限制了,爲何須要作限制?

假設我有一張紋理是960x640大小的,在iphone上鋪滿整屏,根據咱們的設置(FixedSize和Manual Height=640),拿到1024x768的分辨率上,高度640 / 768 = 0.83,爲了保證等比縮放,寬度960 / 0.83 = 1156,不幸的事情發生了,1156 > 1024,這個UI組件寬度超過了屏幕的寬度,被裁剪了。。。這是咱們不能容忍的,或許你能夠說咱們儘可能不作這種尺寸的UI,OK,你能夠對UI尺寸加限制,可是當面對android那些奇葩的分辨率的時候,你會發現限制愈來愈大,這也許會讓美術和策劃瘋掉!


6.解決方案

當咱們花上一些時間去觀察如今移動設備的分辨率時,雖然奇葩不少,可是仍是有一些規律的,規律的在於寬高比而不在於具體尺寸,大致上劃分一下寬高比在1.3,1.5,1.7的範圍上的居多(基本是所有吧!)即使是再有1.2,1.8的比例也無妨。。。

NGUI爲咱們提供的方案只有以各類高度爲衡量標準是不夠的,咱們應該加上一種以寬度爲衡量標準的縮放類型

而對於UI資源的標準,咱們選取960x640,寬高比爲1.5

這樣,當咱們在兼容大於1.5的尺寸的時候,使用NGUI的現有方案;當咱們在兼容小於1.5的尺寸的時候,使用以寬度爲衡量標準

也就是說有一個相似Manual Width的屬性,當小於1.5時,咱們使用Manual Width / Screen Width得出整棵UI樹的縮放比例!

這樣作的好處是「黑邊」區域不會太大,而且不須要對UI組件的大小作限制!


PS: 我表示以上言論對於「能夠爲適配分辨率作無數套圖的資源土豪」而言多是我想多了!

http://blog.csdn.net/asd237241291/article/details/8126619

 

原創文章如需轉載請註明:轉載自 脫莫柔Unity3D學習之旅 本文連接地址:Unity3D NGUI自適應屏幕分辨率

1.UIRoot:根據高度自適應屏幕分辨率。

NGUI根目錄的UIRoot組件自帶了根據高度自適應分辨率的功能。

Scaling Style屬性可選擇三種不一樣的縮放策略。

  1. PixelPerfect 完美像素:直接顯示設定好的像素。當屏幕高度低於minimum Height時按比例縮小,當屏幕高度大於maximum Height時按比例擴大。

  2. FixedSize 按比例縮放:在設定好的基礎上,直接按比例縮放。

  3. FixedSizeOnMobiles 合體版,android和ios爲FixedSize方式,其它按照PixelPerfect方式。

// FixedSize時:填理想分辨率的高度
// FixedSizeofWidth時:填理想分辨率的寬度

Manual Height:先按照理想分辨率作。當Game視圖(打包後的屏幕分辨率)不是這個理想分辨率的時候就會進行比例縮放。


Minimum Height:Game視圖低於這個數值開始按比例縮放。
Maximum Height:Game視圖高於這個數值開始按比例縮放。


這三種縮放方式所有都是按照高度計算縮放比例,徹底忽略寬度。

在製做時UI比例按照最長的16:9(紅色)來作,另外3:2(綠色)爲內容區域。紅色兩邊的位置在不一樣比例的手機上會有不一樣程度的別切割的狀況,因此不要把遊戲內容放在這一區域。



2.UIRoot:根據寬度自適應屏幕分辨率。

UIRoot已經實現了根據高度自適應的功能,可是我現的需求是要根據寬度來自適應,屏幕高度高於UI高度則留空白。


1.首先給UIRoot增長一種狀態

[csharp] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. public enum Scaling  

  2. {  

  3.     PixelPerfect,  

  4.     FixedSize,  

  5.     FixedSizeOnMobiles,  

  6.         /// <summary>  

  7.         /// 根據寬度適配  

  8.         /// </summary>  

  9.         FixedSizeofWidth,  

  10. }  

public enum Scaling
{
	PixelPerfect,
	FixedSize,
	FixedSizeOnMobiles,
        /// <summary>
        /// 根據寬度適配
        /// </summary>
        FixedSizeofWidth,
}

2.實現仍是須要FixedSize的算法,因此須要修改兩個判斷語句

修改1:

[csharp] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. public float GetPixelSizeAdjustment (int height)  

  2. {  

  3.     height = Mathf.Max(2, height);  

  4.         //修改1  

  5.         if (scalingStyle == Scaling.FixedSize || scalingStyle == Scaling.FixedSizeofWidth)  

  6.         return (float)manualHeight / height;  

  7.  

  8. #if UNITY_IPHONE || UNITY_ANDROID  

  9.     if (scalingStyle == Scaling.FixedSizeOnMobiles)  

  10.         return (float)manualHeight / height;  

  11. #endif  

  12.     if (height < minimumHeight) return (float)minimumHeight / height;  

  13.     if (height > maximumHeight) return (float)maximumHeight / height;  

  14.     return 1f;  

  15. }  

public float GetPixelSizeAdjustment (int height)
{
	height = Mathf.Max(2, height);
        //修改1
        if (scalingStyle == Scaling.FixedSize || scalingStyle == Scaling.FixedSizeofWidth)
		return (float)manualHeight / height;

#if UNITY_IPHONE || UNITY_ANDROID
	if (scalingStyle == Scaling.FixedSizeOnMobiles)
		return (float)manualHeight / height;
#endif
	if (height < minimumHeight) return (float)minimumHeight / height;
	if (height > maximumHeight) return (float)maximumHeight / height;
	return 1f;
}

修改2:

[csharp] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. public int activeHeight  

  2. :{  

  3.     get  

  4.     {  

  5.         int height = Mathf.Max(2, Screen.height);  

  6.         //修改2  

  7.         if (scalingStyle == Scaling.FixedSize || scalingStyle == Scaling.FixedSizeofWidth)   

  8.             return manualHeight;  

  9. #if UNITY_IPHONE || UNITY_ANDROID  

  10.         if (scalingStyle == Scaling.FixedSizeOnMobiles)  

  11.             return manualHeight;  

  12. #endif  

  13.         if (height < minimumHeight) return minimumHeight;  

  14.         if (height > maximumHeight) return maximumHeight;  

  15.         return height;  

  16.     }  

  17. }  

public int activeHeight
:{
	get
	{
		int height = Mathf.Max(2, Screen.height);
		//修改2
		if (scalingStyle == Scaling.FixedSize || scalingStyle == Scaling.FixedSizeofWidth) 
			return manualHeight;
#if UNITY_IPHONE || UNITY_ANDROID
		if (scalingStyle == Scaling.FixedSizeOnMobiles)
			return manualHeight;
#endif
		if (height < minimumHeight) return minimumHeight;
		if (height > maximumHeight) return maximumHeight;
		return height;
	}
}


3.增長按寬度自適應算法

[csharp] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. void Update ()  

  2. {  

  3. #if UNITY_EDITOR  

  4.     if (!Application.isPlaying && gameObject.layer != 0)  

  5.         UnityEditor.EditorPrefs.SetInt("NGUI Layer", gameObject.layer);  

  6. #endif  

  7.     if (mTrans != null)  

  8.     {  

  9.         float calcActiveHeight = activeHeight;  

  10.   

  11.         if (calcActiveHeight > 0f )  

  12.         {  

  13.             float size = 2f / calcActiveHeight;  

  14.   

  15.             //看這裏,看這裏,看這裏  

  16.             if (scalingStyle == Scaling.FixedSizeofWidth)  

  17.                     {  

  18.                 float radio = (float)Screen.width / Screen.height;  

  19.                 size = size * radio;  

  20.             }  

  21.   

  22.             Vector3 ls = mTrans.localScale;  

  23.   

  24.             if (!(Mathf.Abs(ls.x - size) <= float.Epsilon) ||  

  25.                 !(Mathf.Abs(ls.y - size) <= float.Epsilon) ||  

  26.                 !(Mathf.Abs(ls.z - size) <= float.Epsilon))  

  27.             {  

  28.                 mTrans.localScale = new Vector3(size, size, size);  

  29.             }  

  30.         }  

  31.     }  

  32. }  

void Update ()
{
#if UNITY_EDITOR
	if (!Application.isPlaying && gameObject.layer != 0)
		UnityEditor.EditorPrefs.SetInt("NGUI Layer", gameObject.layer);
#endif
	if (mTrans != null)
	{
		float calcActiveHeight = activeHeight;

		if (calcActiveHeight > 0f )
		{
			float size = 2f / calcActiveHeight;

			//看這裏,看這裏,看這裏
			if (scalingStyle == Scaling.FixedSizeofWidth)
	                {
				float radio = (float)Screen.width / Screen.height;
				size = size * radio;
			}

			Vector3 ls = mTrans.localScale;

			if (!(Mathf.Abs(ls.x - size) <= float.Epsilon) ||
			    !(Mathf.Abs(ls.y - size) <= float.Epsilon) ||
			    !(Mathf.Abs(ls.z - size) <= float.Epsilon))
			{
				mTrans.localScale = new Vector3(size, size, size);
			}
		}
	}
}


3.UIStretch:根據寬度自適應屏幕分辨率。(NGUI3.0.7版本後再也不支持)

這個是早期NGUI實現自適應分別率的一種方法,新版本中加入UIRoot自適應的方法後,這個腳本就不在被官方推薦使用了。


這個腳本自帶的Style除了按高度自適應的功能以外,按寬度自適應是要拉伸圖像的,並不能知足咱們的要求。

最符合咱們的要求的就是BasedOnHeight,那咱們就按照這個功能修改一個BasedOnWidth出來,以前的博客中寫過這個功能,如今這篇文章直接替換了以前的,因此我仍是貼出修改的內容吧。

首先在Style枚舉中增長一個BasedOnWidth,類型

[csharp] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. public enum Style  

  2. {  

  3.     None,  

  4.     Horizontal,  

  5.     Vertical,  

  6.     Both,  

  7.     BasedOnHeight,  

  8.         BasedOnWidth,  

  9.     FillKeepingRatio,   

  10.     FitInternalKeepingRatio  

  11. }  

public enum Style
{
	None,
	Horizontal,
	Vertical,
	Both,
	BasedOnHeight,
        BasedOnWidth,
	FillKeepingRatio, 
	FitInternalKeepingRatio
}

Update方法中增長一個if分支。

[csharp] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. if (style == Style.BasedOnHeight)  

  2. {  

  3.     localScale.x = relativeSize.x * rectHeight;  

  4.     localScale.y = relativeSize.y * rectHeight;  

  5. }else if (style == Style.BasedOnWidth)  

  6. {  

  7.         localScale.x = relativeSize.x * rectWidth;  

  8.         localScale.y = relativeSize.y * rectWidth;   

  9. }  

  10. else if (style == Style.FillKeepingRatio)  

  11. {……}  

	if (style == Style.BasedOnHeight)
	{
		localScale.x = relativeSize.x * rectHeight;
		localScale.y = relativeSize.y * rectHeight;
	}else if (style == Style.BasedOnWidth)
	{
	        localScale.x = relativeSize.x * rectWidth;
	        localScale.y = relativeSize.y * rectWidth; 
	}
	else if (style == Style.FillKeepingRatio)
	{……}

這個腳本是經過拉伸scale實現,因此這個腳本要放在你須要拉伸的UI上(若是你只須要一個背景圖片自適應屏幕分辨率,那就把這個腳本添加到這個背景圖片中,若是要一個panel內全部元素都自適應,那就放在這個panel上。若是想讓全部的UI所有自適應分辨率,那就放在NGUI的cameta上。)

ui Camera屬性須要選擇渲染當前UI的攝像機。

使用步驟:

1.把Game視圖設定一個最理想的寬度(之後按照這個比例縮放。)。

2.按需求選擇一個放置UIStretch的物體,而後添加這個組件。並將ui cameta賦值。

3.將ui cameta的Size修改成當前屏幕的寬度。(這個物體的Scale的X、Y已經被UIStrech設置爲屏幕寬度,此值不能被修改。)

4.這個時候改變窗口寬度,只有該物體Scale 的X、Y已被自動修改,UI視圖已自動適應~!

相關文章
相關標籤/搜索