這裏咱們先談第一個問題座標矩陣變化實現佈局自適應。iphone
一般你須要選擇一個基準的屏幕尺寸,象如今開發的應用也須要跨平臺在iOS(iPhone/iPad)/Android均可以運行,我這邊選取的是iphone4的屏幕尺寸: 480 * 320. 設計師設計的GUI的素材時就是按照這個尺寸來設計。可是緊接着的問題是如何保證它在其餘不一樣尺寸/分辨率的平臺上運行時不會出現各類詭異的位置大小錯亂了。ide
舉一個實際的例子來更好描述這個問題,好比咱們的遊戲是水平方向的, 而後遊戲進行中間的暫停界面中,有三個角落有按鈕或着標籤,屏幕中間有一個按鈕,以下圖所示:佈局
很簡單的代碼:ui
void OnGUI()
{
GUI.Box(new Rect(15 , 10, 83, 49), bg_score);
GUI.Box(new Rect(372, 10, 98, 44), bg_time);
if (GUI.Button(new Rect(5, 280, 67, 41), bt_pause))
{
//pause the scene
}
}
在Unity中咱們將Game窗口的模式選擇爲iPhone Wide(480x320), 而後運行遊戲, 木有什麼問題。 緊接着嘗試運行在iPhone 4G Wide(960x640), 你就會發現問題了,整個格局錯亂了,並無有比例的伸縮,而後所有堆到了左邊.this
因此能夠想到既然有了基準的屏幕尺寸,其餘尺寸的處理必然須要針對這個基準來變化, 咱們須要的是在基準屏幕上各個元素都按照必定的比例放大或者縮小,水平和豎直方向的伸縮比列必定得是同步的,這樣一來保證它們之間的相對位置保持不變。在Unity中GUI系統中咱們就須要運用到GUI.Matrix矩陣變化。spa
要解決這個問題,咱們能夠定義一個基準尺寸,咱們這裏是480*320.設計
public static Vector2 NativeResolution = new Vector2(480, 320);
而後了,咱們要讓長寬按照這個基準來變化,包括首先是伸縮放大或縮小,其次是在變化以後使其保持居中。code
private static float _guiScaleFactor = -1.0f;
private static Vector3 _offset = Vector3.zero;
static List<Matrix4x4> stack = new List<Matrix4x4> ();
public void BeginUIResizing()
{
Vector2 nativeSize = NativeResolution;
_didResizeUI = true;
stack.Add (GUI.matrix);
Matrix4x4 m = new Matrix4x4();
var w = (float)Screen.width;
var h = (float)Screen.height;
var aspect = w / h;
var offset = Vector3.zero;
if(aspect < (nativeSize.x/nativeSize.y))
{
//screen is taller
_guiScaleFactor = (Screen.width/nativeSize.x);
offset.y += (Screen.height-(nativeSize.y*guiScaleFactor))*0.5f;
}
else
{
// screen is wider
_guiScaleFactor = (Screen.height/nativeSize.y);
offset.x += (Screen.width-(nativeSize.x*guiScaleFactor))*0.5f;
}
m.SetTRS(offset,Quaternion.identity,Vector3.one*guiScaleFactor);
GUI.matrix *= m;
}
public void EndUIResizing()
{
GUI.matrix = stack[stack.Count - 1];
stack.RemoveAt (stack.Count - 1);
_didResizeUI = false;
}
緊着這咱們在OnGUI方法中的開頭和結尾分別調用BeginUIResizing和EndUIResizing來變化矩陣。遊戲
void OnGUI()
{
BeginUIResizing(); //call this in the beginning of method
GUI.Box(new Rect(15 , 10, 83, 49), bg_score);
GUI.Box(new Rect(372, 10, 98, 44), bg_time);
if (GUI.Button(new Rect(5, 280, 67, 41), bt_pause))
{
//pause the scene
}
EndUIResizing(); //call this in the end of method
}
這裏咱們根據長寬比,算出伸縮比例,而後爲了保證伸縮以後的畫面能始終在屏幕中間,咱們要算出多出來偏移量,最後咱們根據這個偏移量和縮放比例對矩陣進行變化。ip
而後咱們再在分辨率爲960*640的狀況下運行。
你能夠看到在其餘尺寸的屏幕上伸縮都沒有問題,並且元素都居中。可是有一個問題,你發如今iPhone5和iPad上幾個標籤按鈕的位置有點不太對,他們須要像iPhone4同樣緊貼兩邊,而在iPhone5和iPad上卻不是這樣。
要想解決這個問題的理解這個矩陣變化是如何工做的。這個偏移量是變換以後算出來的偏移量。因此要想讓GUI元素在變換以後依然在保持屏幕的邊緣,咱們須要將x,y減去這偏移量,因而有了下面的代碼:
void OnGUI()
{
BeginUIResizing(); //call this in the beginning of method
GUI.Box(new Rect(15 - offset.x/guiScaleFactor , 10 - offset.y/guiScaleFactor,
83, 49), bg_score);
GUI.Box(new Rect(372 + offset.x/guiScaleFactor, 10 - offset.y/guiScaleFactor,
98, 44), bg_time);
if (GUI.Button(new Rect(5 - offset.x/guiScaleFactor, 280 + offset.y/guiScaleFactor,
67, 41), bt_pause))
{
//pause the scene
}
EndUIResizing(); //call this in the end of method
}
這裏要記住這個偏移量是offset.x/guiScaleFactor, 而不是offset.x, 由於這個座標是基於基準矩陣來的。
將代碼從新跑一遍:
這個木有問題了。