现在用unity做项目 90%都是用NGUI,并且我个人觉得NGUI应该算是比较成熟的UI插件,虽然他也存在很多问题,但是至少这么多游戏都在用,它目前是能hold住的,嘿嘿。 这篇文章说说我现在是怎么自适应UI 和 3D 游戏的。。
1.获取屏幕的宽高
Screen.width Screen.height 可以回去设备屏幕的宽高,但是它并不是NGUI的宽高。比如你想做一个全屏的UISprite 。
这样的代码是错误的。
sprite.width = Screen.width ;
sprite.height = Screen.height
正确的方法应该是:
1 2 3 4 5 6 7 8 9 10 |
UIRoot root = GameObject.FindObjectOfType<UIRoot>(); if (root != null) { float s = (float)root.activeHeight / Screen.height; int height = Mathf.CeilToInt(Screen.height * s); int width = Mathf.CeilToInt(Screen.width * s); Debug.Log("height = " + height); Debug.Log("width = " + width); } |
我建议在项目中你可以封装两个只读的方法来获取NGUI 的宽和高。
2.自适应NGUI屏幕
在Hierarchy视图中选择UI Root (2D)然后在Inspector视图中、
Scaling Style :如果是手机游戏的就选择FixedSizeOnMobiles,它的意思就是开启UI整体缩放的支持。
Manual Height:这个属性就比较重要的,因为我们的自适应屏幕,原理就是根据Screen.width 和Screen.height来动态的计算它的实际高度,动态的修改这个值。
Min/Max inum Height:这就是支持的最大高度,和最小高度一般都是 640 到 1536。
开始做UI的时候就需要定制游戏主版本的屏幕分辨率,我定的分辨率是960X640,所以我屏幕的实际高度是640 。那么在Manual Height的参数我就需要写640.
如下图所示,我在960X640的屏幕上布置了我的简单界面。
我举个典型的例子,这时候我把屏幕分辨率改成1024X768. 因为960X640 是3:2的屏幕,而1024X768是4:3的屏幕。所以屏幕就会变成那面这个样子。
然后,我们就需要来修改Manual Height这个参数,如果是1024X760的分辨率,那么此时它的Maunal Height应该是720。
在看看,如下图所示,界面整体布局居中显示了。但是布局的位置是没有发生任何改变的。
我个人觉得根本就是没有完美自适应的方法。除非你可以接收屏幕上的某些元素被拉伸变形。。 如上图所示,在这里我们只需要把背景的白框拉伸成屏幕的宽高即可。
说了半天就是一个简单的数学算法,根据布置UI时的分辨率,加上现在屏幕的分辨率根据这两个参数,动态的计算出现在manualHeight的高度。
我在Unity圣典上已经看到有人写了这个算法。
http://game.ceeger.com/forum/read.php?tid=9230&ds=1
找一个合适的地方调用一下如下方法。 960 /640换成你布置屏幕时的宽高即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
static private void AdaptiveUI() { int ManualWidth = 960; int ManualHeight = 640; UIRoot uiRoot = GameObject.FindObjectOfType<UIRoot>(); if (uiRoot != null) { if (System.Convert.ToSingle(Screen.height) / Screen.width > System.Convert.ToSingle(ManualHeight) / ManualWidth) uiRoot.manualHeight = Mathf.RoundToInt(System.Convert.ToSingle(ManualWidth) / Screen.width * Screen.height); else uiRoot.manualHeight = ManualHeight; } } |
UI整体布局 “居中” 并不是一个好的处理办法,这时候就需要策划人员的头脑风暴了,不过可以参考一下别的游戏自适应的方法。如果你的UI布局比较简单的话,比如战斗UI。一般都是4个角有东西,可以用Anchor把它固定在屏幕上。或者用新版本的NGUI提供的UIWidget也可以设置固定的位置。
3.3D方面的自适应
我们在说说3D方面的自适应,比如游戏里面的人物。。我举个例子,比如我们游戏是960X640屏幕,在屏幕的边缘放一个3D的角色,那么此时屏幕变成1024×768那么这个小人可能就跑到屏幕外面了。。解决这个问题就需要3D 摄像机的自适应。
如下图所示,我在960X640屏幕的边缘放了一个3D的立方体对象。
然后我把屏幕设置成1024X768。如下图所示,可以看到这个立方体对象以后超出了屏幕。。。
有一个非常俏巧妙的方法可以解决它。就是修改Camera的Field of View的参数,找一个合适的地方调用一下这个方法。这里我借助了刚刚自适应NGUI屏幕的参数。这里我用到了UIRoot的manualHeight ,所以UI需要你是用上面介绍的方法来自适应,640表示我制作时屏幕的高度,拥着两个数相除那么就可以得到Camera缩放的系数了。
1 2 3 4 5 6 7 8 |
static public float getCameraFOV(float currentFOV) { UIRoot root = GameObject.FindObjectOfType<UIRoot>(); float scale =Convert.ToSingle(root.manualHeight / 640f); return currentFOV * scale; } |
找一个合适的地方调用,60表示默认的参数,getCameraFOV这个方法的原理就是根据默认的FOV参数加上当前屏幕的系数以及布置屏幕时的系数,动态计算出一个新的FieldOfView。
1 2 3 |
Camera.main.fieldOfView = getCameraFOV(60); |
说到这里其实修改射线机的Z轴也可以达到自适应的效果,但是我觉得最好用fieldofView,因为游戏中你的摄像机可能位置会发生变化,总不能一直去改Z轴的属性吧,而FiewldOfView你只需要设置一次就可以了。嘿嘿。
4.拉伸变形
你可以让所有的摄像机在初始化的时候调用一下这个方法,它会完完整整的拉伸屏幕 ,大家可以试试,不过千万不要用,因为变形了太难看。。。。
1 2 3 4 5 6 |
foreach(Camera camera in Camera.allCameras) { camera.aspect = 640f/960f; } |
- 本文固定链接: https://www.xuanyusong.com/archives/2536
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
momo大神 但我界面中有 setactive(ture)时 界面会鬼畜一下 ,变大又变小 怎么解决啊
本来是来学习的, 结果看你提到‘鬼畜’, 然后我就看了一下午的鬼畜。。。
1024*768 为何高度要设为720, 是如何计算出来的?
MoMo大神,UIROOT(3D)可以根据屏幕大小来移动摄像机,实现大小适应,再改下Anchors来适应位置,可以用3DUIRoot来替代2D的么?
请问 , UGUI 的 Text 怎么根据 内容 自适应宽度呢?
wdith 和heigh设置成0 下面 horizontal 和 vertical 设置成overflow 就行了。。
MoMo大神:在不同的分辨率下如何保持菜单在屏幕的最上方。
ngui可以挂Anchor ugui也可以。。
Mo大,请问关于你这篇文章自适应后两边会有后面摄像机的空白漏出来,你是怎么处理的?是用图片遮挡,还是调整Anchors和Aspect,让精灵图片适应屏幕宽度?第二种方式我认为应该要好些,只是有缺陷,不能整体控制。
Anchors 在比较简单的界面上可以, 比如战斗界面 放在四个角上。 而真正的界面是很复杂的,用anchors就变形了。。 所以 露出来的地方 我们的设计是 整体界面居下, 然后上下各有两个条 。这两个条的宽度和屏幕宽度一样。。
自适应屏和列表滑动有冲突 怎么破?
momo,你好,请问你知道在NGUI中怎么把两个模型在一个摄像机中分开区域显示吗?我试了用两个panel调为soft clip,改变size给定显示区域,但是效果是它只能隔开精灵图片,不能隔开模型的显示,为什么呢,我用的是3D UI Camera