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时动态的切换,使用者也许能更清楚它们之间的关系)学习
这是一个简单的枚举变量,包括三个枚举值ui
[csharp] view plaincopyprint?spa
public enum Scaling .net
{ 设计
PixelPerfect,
FixedSize,
FixedSizeOnMobiles,
}
public enum Scaling
{
PixelPerfect,
FixedSize,
FixedSizeOnMobiles,
}
(FixedSize和FixedSizeOnMobiles相似,而且后者只添加了对ios和android平台的判断,因此前者能够替代后者使用)
这里只讨论PixelPerfect和FixedSize的区别,二者都是针对于全部在此UIRoot之下的UI组件而言的,也能够认为是在此UIRoot下,整个游戏屏幕的尺寸的缩放类型!
Manual Height和Minimum Height, Maximum Height不会同时对此UIRoot起做用,当选择Scaling Style为PixelPerfect时,咱们须要设置Minimum Height, Maximum Height;而当Scaling Style为FixedSize或FixedSizeOnMobiles时,咱们须要设置Manual Height。(这就是我前面吐槽的缘由)
这个组合主要用于咱们指望全部的UI纹理都“尽可能”不进行缩放,所谓“尽可能”的程度,则是取决于Minimum Height和Maximum Height,Minimum Height表示当设备分别率小于此设置值时,根据此设置值对UIRoot进行缩放;Maximum Height表示当设备分辨率大于此设置值时,根据此设置值对UIRoot进行缩放(UIRoot是UI游戏对象树的根,修改UIRoot的缩放,则会影响整棵UI树的缩放)
这个组合主要用于咱们指望全部的UI纹理都进行“合适”的缩放,所谓“合适”缩放的原则,则是根据Manual Height设置值,当设备分辨率的高度值不一样于此设置值时,则根据其比例(即Manual Height / Screen Height)对整棵UI树的进行“等比”缩放(宽度的缩放比也是此比例值),这样,咱们就能够作一套资源,在不一样尺寸的分辨率最好的“不变形”的适配了
前面两组在什么状况下等同呢?
Manual Height == Minimum Height == Maximum Height
推导过程,呵呵~~
具体可参考UIRoot中activeHeight属性和GetPixelSizeAdjustment的计算过程
基于以上推到,当咱们以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以后,黑边的相对比例会更大。。。
假设咱们的游戏类型更适合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那些奇葩的分辨率的时候,你会发现限制愈来愈大,这也许会让美术和策划疯掉!
当咱们花上一些时间去观察如今移动设备的分辨率时,虽然奇葩不少,可是仍是有一些规律的,规律的在于宽高比而不在于具体尺寸,大致上划分一下宽高比在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自适应屏幕分辨率
NGUI根目录的UIRoot组件自带了根据高度自适应分辨率的功能。
Scaling Style属性可选择三种不一样的缩放策略。
PixelPerfect 完美像素:直接显示设定好的像素。当屏幕高度低于minimum Height时按比例缩小,当屏幕高度大于maximum Height时按比例扩大。
FixedSize 按比例缩放:在设定好的基础上,直接按比例缩放。
FixedSizeOnMobiles 合体版,android和ios为FixedSize方式,其它按照PixelPerfect方式。
// FixedSize时:填理想分辨率的高度
// FixedSizeofWidth时:填理想分辨率的宽度
Manual Height:先按照理想分辨率作。当Game视图(打包后的屏幕分辨率)不是这个理想分辨率的时候就会进行比例缩放。
Minimum Height:Game视图低于这个数值开始按比例缩放。
Maximum Height:Game视图高于这个数值开始按比例缩放。
这三种缩放方式所有都是按照高度计算缩放比例,彻底忽略宽度。
在制做时UI比例按照最长的16:9(红色)来作,另外3:2(绿色)为内容区域。红色两边的位置在不一样比例的手机上会有不一样程度的别切割的状况,因此不要把游戏内容放在这一区域。
UIRoot已经实现了根据高度自适应的功能,可是我现的需求是要根据宽度来自适应,屏幕高度高于UI高度则留空白。
[csharp] view plaincopyprint?
public enum Scaling
{
PixelPerfect,
FixedSize,
FixedSizeOnMobiles,
/// <summary>
/// 根据宽度适配
/// </summary>
FixedSizeofWidth,
}
public enum Scaling
{
PixelPerfect,
FixedSize,
FixedSizeOnMobiles,
/// <summary>
/// 根据宽度适配
/// </summary>
FixedSizeofWidth,
}
[csharp] view plaincopyprint?
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;
}
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;
}
[csharp] view plaincopyprint?
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;
}
}
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;
}
}
[csharp] view plaincopyprint?
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);
}
}
}
}
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);
}
}
}
}
这个是早期NGUI实现自适应分别率的一种方法,新版本中加入UIRoot自适应的方法后,这个脚本就不在被官方推荐使用了。
这个脚本自带的Style除了按高度自适应的功能以外,按宽度自适应是要拉伸图像的,并不能知足咱们的要求。
最符合咱们的要求的就是BasedOnHeight,那咱们就按照这个功能修改一个BasedOnWidth出来,以前的博客中写过这个功能,如今这篇文章直接替换了以前的,因此我仍是贴出修改的内容吧。
首先在Style枚举中增长一个BasedOnWidth,类型
[csharp] view plaincopyprint?
public enum Style
{
None,
Horizontal,
Vertical,
Both,
BasedOnHeight,
BasedOnWidth,
FillKeepingRatio,
FitInternalKeepingRatio
}
public enum Style
{
None,
Horizontal,
Vertical,
Both,
BasedOnHeight,
BasedOnWidth,
FillKeepingRatio,
FitInternalKeepingRatio
}
Update方法中增长一个if分支。
[csharp] view plaincopyprint?
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)
{……}
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视图已自动适应~!