Unity屏幕自适应原理

Wesley13
• 阅读 498

本节记录内容来自于siki学院的“暗黑战神”系列

  先讲一下自适应问题的来源:

  Unity屏幕自适应原理

  如上图所示,我们现在的画布里有两个按钮,且当前屏幕分辨率设为了1334*750。

  假如我们改变一下屏幕分辨率,改为2668*1500后,效果如下图所示:

   Unity屏幕自适应原理   

  这代表当我们实际使用不同尺寸的手机屏幕时,会出现图片显示不全的情况,显然这是不行的。

  来看一下问题的根源:

 Unity屏幕自适应原理  Unity屏幕自适应原理

  如上图所示,左侧和右侧分别是当分辨率被设为1334*750和2668*1500时对应的画布控件的Inspector面板,可以看到,随着分辨率的调节,画布的宽度和高度也被自动地调节了,这就是为什么会不匹配的原因,画布被自动调节到2倍宽高,两个按钮位置自然也不对了。

  那么现在有两种解决方案:一是当分辨率改变时,让画布进行特定的缩放,而不是死板地只让画布的宽高与分辨率相同。二是让两个按钮维持原先大小,但移动位置,仍旧固定在左下角和右上角。我们应该用哪一种呢?

  先看第一种,第一种方案主要通过修改上图中的Canvas Scaler(Script)面板来实现,比如:

Unity屏幕自适应原理 Unity屏幕自适应原理

  如上面两张图所示,此时我们调节了Scale Factor为2,可以看到虽然屏幕分辨率为2668*1500,但显示仍旧正常,再仔细看一下,发现此时画布的宽高为1334*750,而不是2668*1500,已经与屏幕分辨率不同了,这个Scale Factor可以使你的画布的宽高与屏幕分辨率保持一个固定比例。

  显然,利用这个Scale Factor,假如我们写一个脚本,获取屏幕的分辨率,然后算出一个相对我们设计时参考屏幕尺寸的比值,然后对应去修改Scale Factor,可以完成方案一。

  但其实Unity有内置的机制来完成方案一:在Canvas Scaler(Script)面板中,有个UI Scale Mode选项卡,可以选Scale With Screen Size(默认为Constant Pixel Size),意思是根据实际屏幕的尺寸来自动调节画布缩放因子Scale Factor,选择后要设置一个参考尺寸,下面有个Match选项,可以选择是以高度还是宽度为参考,如下图所示:

Unity屏幕自适应原理

比如这里设置了参考尺寸是1334*750,而且是以高度为参考,意思是当实际屏幕尺寸不等于参考尺寸的高度(这里是750)时,会按比例设置缩放因子。这时如果再调节分辨率为2668*1500,由于1500/750=2,相当于自动设置了缩放因子为2,因此会发现完美适配,对应的画布宽高仍为1334*750。

但这就带来了新的问题,缩放因子是以宽或高中的一种作为参考来设置的,如果像上面那样,等比例缩放还好,假若宽高比不同呢?比如若屏幕分辨率是1024*768,按照之前的说法,此时画布的宽度会变成1024/(768/750)=1000,高度为750,我们来验证一下: 

Unity屏幕自适应原理 Unity屏幕自适应原理

  如上图所示,画布的宽度变成了999.9999近似1000,没问题。

  但很明显,现在这个策略就会出现问题,等比例缩放后两个按钮已经看不到了,怎么办呢?

  显然,这就必须要配合第二种方案,即让两个按钮位置移动,维持在两个角落。

  在说第二种方案前,先要考虑这样一个问题:自适应的时候能不能只使用第二种方案,也就是说只固定两个按钮到边界的距离,完全不用第一种方案,不使用缩放?

  答案是不行,仔细想想就知道,这样就会出现屏幕尺寸整体扩大后,两个按钮显得过小的问题,所以缩放是必须要的。

  那么到底应该以宽度为准,还是以高度为准?

  我们知道,当前的手机屏幕,各种不同大小屏幕的手机,在竖屏高度上差别挺大的,在宽度上变化就小很多。那么对应的,当设计横屏游戏时,可以认为不同机型的横屏宽度变化很大,高度变化很小。那么显然我们以高度为缩放标准更合适,这样不同机型的缩放程度也就不大,对应UI的尺寸变化也就不大,当然,同理地,当设计竖屏游戏时,就应该以宽度为缩放标准。

  那我们已经决定了在设计横屏游戏时以高度为缩放基准,那么就要解决之前说的实际宽高比与基准宽高比不同的问题了。

  这个问题可以通过设置锚点来解决,如下图所示:

  Unity屏幕自适应原理  Unity屏幕自适应原理

  对左下角的按钮,设置锚点在左下角,右上角的设置在右上角即可,此时效果如下: 

  Unity屏幕自适应原理

  可以看到,即使在1024*768的分辨率下,依旧适配良好。

  但需要注意的一点是,实际开发中,会有很多界面,比如登录界面,注册界面等等,为了更好的区分这些界面,防止不同界面的UI发生混淆,通常的手法是在场景中创建一个空物体,把该界面的UI元素都挂载到该空物体下,这样当开发下一个界面时,我们只需要简单地让开发好的界面的空物体不显示即可。如下图所示,panel就是那个空物体

Unity屏幕自适应原理

  但这样会在屏幕适配的时候碰到问题,如果把两个Button分别锚定到左上角和右下角,会固定到它们的父物体上,也就是这个panel空物体上,显然这样就无法固定到左下角和右上角了。

  解决的方案是把这个空物体铺满整个画布,操作如下图所示:

Unity屏幕自适应原理   Unity屏幕自适应原理

  为空物体选择伸展方式后,记得设置左右上下为0,这代表该物体离父物体(这里是画布)的左,右,上,下边的距离,设为0就是完全铺满画布。这样就完成了,具体效果图就不展示了,完美自适应。

  这样就结束了吗?NoNoNo。

  对于普通控件,这样无疑已经够了,但假如我们在界面里放了张背景图,这个图片作了以高度为基准的自适应,且用锚点铺满了整个画布。这个时候假如屏幕的高度发生了变化,按照之前说的,若以高度为基准,则高度不变,画布会自动对宽度进行缩放,而这时由于背景图片已经被锚定铺满了整个画布,因此背景图片会出现拉伸或压缩。这会影响观感,该怎么办呢?

  通常的实际项目开发做法如下:对界面中的其它元素,仍按之前说的,用空物体容纳,空物体锚定并铺满画布,这些元素就锚定到空物体上。而对于背景图,则特殊处理,不要让它锚定并铺满画布,而是让它使用默认的铺展方式,即居中,如下图所示:

  Unity屏幕自适应原理

  而且这个背景图需要做得比画布更大一些,假设是以高度为基准的缩放,那么此时高度会一直维持,宽度会根据屏幕进行缩放,所以只需要把背景图的宽度做得比参考尺寸大即可,这样,一开始我们不会展示全部的背景图,当屏幕的高度发生改变时,比如高度变小了,按之前说的,由于是高度为基准,因此画布会进行缩放,即高度维持基准值,而为了保证宽高比不变,必然导致画布宽度增大。就可以展示更多的内容,而且不会有图片被压缩的问题。

   示意图如下:

Unity屏幕自适应原理

Unity屏幕自适应原理   Unity屏幕自适应原理

最上面一张是初始图,此时分辨率为1334*750,背景的红色图片高度与画布相同,宽度要大于画布,此时仅展示了一部分背景。

下面两张图是把屏幕高度调节后的结果图,左边那张是把高度调低了,此时由于以高度为基准缩放的原因,画布高度一致保持不变,为了保持宽高比,画布的宽度会增加,到超过极限后画布的宽度会大于背景图的宽度,导致显示出问题,因此设计背景图大小时要注意,预留出的宽度(以高度为缩放基准的情况下)要考虑到屏幕的极限情况,保证预留宽度要满足即使在实际屏幕宽高比最极限的情况下图片也能正常显示。

同理,右边那张就是高度调高后的情况,调高后为了让画布高度保持不变,在宽高比的限制下会导致宽度减小,就是右图的样子了。

完毕。

点赞
收藏
评论区
推荐文章
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
1年前
​一篇文章总结一下Python库中关于时间的常见操作
前言本次来总结一下关于Python时间的相关操作,有一个有趣的问题。如果你的业务用不到时间相关的操作,你的业务基本上会一直用不到。但是如果你的业务一旦用到了时间操作,你就会发现,淦,到处都是时间操作。。。所以思来想去,还是总结一下吧,本次会采用类型注解方式。time包importtime时间戳从1970年1月1日00:00:00标准时区诞生到现在
Stella981 Stella981
1年前
JS 苹果手机日期显示NaN问题
问题描述newDate("2019122910:30:00")在IOS下显示为NaN原因分析带的日期IOS下存在兼容问题解决方法字符串替换letdateStr"2019122910:30:00";datedateStr.repl
Stella981 Stella981
1年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
1年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序selectfromtable_nameorderiddesc;2.按照指定(多个)字段排序selectfromtable_nameorderiddesc,statusdesc;3.按照指定字段和规则排序selec
Wesley13 Wesley13
1年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Stella981 Stella981
1年前
Angular material mat
IconIconNamematiconcode_add\_comment_addcommenticon<maticonadd\_comment</maticon_attach\_file_attachfileicon<maticonattach\_file</maticon_attach\
Wesley13 Wesley13
1年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
京东云开发者 京东云开发者
1星期前
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
helloworld_34035044 helloworld_34035044
5个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为