NGUI自适应屏幕

转载链接:

http://www.xuanyusong.com/archives/2536


现在用unity做项目 90%都是用NGUI,并且我个人觉得NGUI应该算是比较成熟的UI插件,虽然他也存在很多问题,但是至少这么多游戏都在用,它目前是能hold住的,嘿嘿。 这篇文章说说我现在是怎么自适应UI 和 3D 游戏的。。

1.获取屏幕的宽高

Screen.width  Screen.height 可以回去设备屏幕的宽高,但是它并不是NGUI的宽高。比如你想做一个全屏的UISprite 。

这样的代码是错误的。

sprite.width = Screen.width ;

sprite.height =  Screen.height 

正确的方法应该是:

1 UIRoot root = GameObject.FindObjectOfType<UIRoot>();
2 if (root != null) {
3     float s = (float)root.activeHeight / Screen.height;
4     int height =  Mathf.CeilToInt(Screen.height * s);
5     int width = Mathf.CeilToInt(Screen.width * s);
6     Debug.Log("height = " + height);
7     Debug.Log("width = " + width);
8 }

 我建议在项目中你可以封装两个只读的方法来获取NGUI 的宽和高。

扫描二维码关注公众号,回复: 3170036 查看本文章

我的注释:

为什么这样不是全屏,因为实际上当我们选择了FixedSizeOnMobiles或者FixedSize的时候,我们最终的元素大小是会进行缩放的。

可以这样理解,我们在设计的时候,会设置屏幕的宽、高(分别叫做mw和mh吧),假定这个叫做设计分辨率(cocos2d-x就是这么叫的),此时我们的一个按钮宽、高为bw和bh。加入我们设定好之后,运行到实际屏幕宽、高为sw和sh上面。

那么unity会根据我们的设置的高和屏幕的高进行比较缩放,以便于我们的高能匹配上屏幕的高。

比如mh为200,sh为400,那么所有元素都会等比扩大2倍。比如mh为400,sh为200,那么所有元素都会等比缩小2倍。

即所有元素的最后(拿按钮来举例)大小为:

float rate = sh / mh;

 h = bh * rate;

w = bw * rate

这就是上面这几条语句的来历:

float s = (float)root.activeHeight / Screen.height;
int height =  Mathf.CeilToInt(Screen.height * s);

int width = Mathf.CeilToInt(Screen.width * s);

设置完之后,把height带进公式计算就可以得出:

h = height * rate = sh * mh / sh * sh / mh = sh;

2.自适应NGUI屏幕

在Hierarchy视图中选择UI Root (2D)然后在Inspector视图中、

Scaling Style :如果是手机游戏的就选择FixedSizeOnMobiles,它的意思就是开启UI整体缩放的支持。

Manual Height:这个属性就比较重要的,因为我们的自适应屏幕,原理就是根据Screen.width 和Screen.height来动态的计算它的实际高度,动态的修改这个值。

Min/Max inum Height:这就是支持的最大高度,和最小高度一般都是 640 到 1536。

屏幕快照 2014-05-04 下午2.03.11

开始做UI的时候就需要定制游戏主版本的屏幕分辨率,我定的分辨率是960X640,所以我屏幕的实际高度是640 。那么在Manual Height的参数我就需要写640.  

如下图所示,我在960X640的屏幕上布置了我的简单界面。

屏幕快照 2014-05-04 下午2.15.16

我举个典型的例子,这时候我把屏幕分辨率改成1024X768. 因为960X640 是3:2的屏幕,而1024X768是4:3的屏幕。所以屏幕就会变成那面这个样子。

屏幕快照 2014-05-04 下午2.23.08

然后,我们就需要来修改Manual Height这个参数,如果是1024X760的分辨率,那么此时它的Maunal Height应该是720。

屏幕快照 2014-05-04 下午2.29.39

在看看,如下图所示,界面整体布局居中显示了。但是布局的位置是没有发生任何改变的。

屏幕快照 2014-05-04 下午2.31.52

我个人觉得根本就是没有完美自适应的方法。除非你可以接收屏幕上的某些元素被拉伸变形。。 如上图所示,在这里我们只需要把背景的白框拉伸成屏幕的宽高即可。

说了半天就是一个简单的数学算法,根据布置UI时的分辨率,加上现在屏幕的分辨率根据这两个参数,动态的计算出现在manualHeight的高度。

我在Unity圣典上已经看到有人写了这个算法。

http://game.ceeger.com/forum/read.php?tid=9230&ds=1

找一个合适的地方调用一下如下方法。 960 /640换成你布置屏幕时的宽高即可。

01 static private void AdaptiveUI()
02 {
03     int ManualWidth = 960;
04     int ManualHeight = 640;
05     UIRoot uiRoot = GameObject.FindObjectOfType<UIRoot>();
06     if (uiRoot != null)
07     {
08         if (System.Convert.ToSingle(Screen.height) / Screen.width > System.Convert.ToSingle(ManualHeight) / ManualWidth)
09             uiRoot.manualHeight = Mathf.RoundToInt(System.Convert.ToSingle(ManualWidth) / Screen.width * Screen.height);
10         else
11             uiRoot.manualHeight = ManualHeight;
12     }
13 }

 我的注释:

if (System.Convert.ToSingle(Screen.height) / Screen.width > System.Convert.ToSingle(ManualHeight) / ManualWidth)
09             uiRoot.manualHeight = Mathf.RoundToInt(System.Convert.ToSingle(ManualWidth) / Screen.width * Screen.height);

因为我们的缩放比都是根据高度来进行缩放的,然后宽度也沿用这个缩放比。但是存在一种可能,就是按照高度的缩放比之后,宽度会超出屏幕的宽度的情形,比如:

sh = 400,sw = 800;

mh = 200,mw = 500;

此时按高度缩放过后,会变成

sh = 400,sw = 800;

mh = 400,mw = 1000;

此时我们在宽度上的显示就会超出屏幕范围,这是我们不能允许的,所以此时就是高度的缩放就需要考虑到宽度了。按照宽度的最大比来,让宽度正好等于屏幕宽度。

sh = 400, sw = 800;

mh =320; mw = 800;

很显然此时高度上会有黑边出现。

另外一种情况是我们按照高度缩放之后,宽度上并没有超出屏幕,此时我们就不用管了。

比如:

sh = 400, sw = 800;

mh= 200, sw = 300;

那缩放之后:

sh = 400, sw = 800;

mh = 400, sw = 600;

此时宽度上会留黑边。

UI整体布局 “居中” 并不是一个好的处理办法,这时候就需要策划人员的头脑风暴了,不过可以参考一下别的游戏自适应的方法。如果你的UI布局比较简单的话,比如战斗UI。一般都是4个角有东西,可以用Anchor把它固定在屏幕上。或者用新版本的NGUI提供的UIWidget也可以设置固定的位置。

猜你喜欢

转载自blog.csdn.net/Monzart7an/article/details/25202601