这里咱们先谈第一个问题坐标矩阵变化实现布局自适应。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, 由于这个坐标是基于基准矩阵来的。
将代码从新跑一遍:
这个木有问题了。