unity循环滚动列表_Unity中实现仿主机游戏的UI动画效果

在UI动画上花费精力,最早是日本的游戏喜欢搞,欧美的游戏都非常不重视(比如暗黑2),其实我也不懂为何日本游戏这么重视这种东西,因为早期做这种东西还挺麻烦的,大概是他们对于小而美的追求吧……总之,后来的欧美游戏把日本游戏的优点全部学了去,铸就了现在的霸主地位。

而这个问题的答案也很简单:设备能跑,为什么不做?为什么其他部分需要动画UI就不需要,难道UI就不算美术的一部分了?

要说我,国内极端不重视UI动画,大概也是受了暗黑等一系列早期欧美游戏的影响。

虽然肯定会有人说自己就是不喜欢UI动画,因为浪费时间,但游戏里什么元素不浪费时间呢?而且苹果的成功,也证实了一般人在娱乐产品里其实是更倾向于有UI动画存在的。

所以我标题上虽然写了主机游戏,指的其实是这种理所应当该有的UI动画,用这个词是方便大家理解,毕竟现在只要是个优秀游戏它的UI动画都是做得很不错的,不管在哪个平台。

这本来就是该做的事。

更何况,实现上,也并不困难。

使用Animator而非DoTween

你我都清楚现在游戏里仅有的UI动画是怎么做的。

但是代码实现的动画其实是很不方便的,它只适用于简单的动画,而且会导致这个工作和技术人员绑定。代替方案也简单,就是Animator。

Animator其实创建动画的操作也不复杂,Ctrl+6打开动画面板然后直接创建就好了,生成的文件可以以后再改名。点击录制然后随便K了就行了,默认的曲线设置大部分情况就够用。

而且生成的动画只要保证每条属性的命名不变,可以在其他地方直接复用,像普通的缩放位移就可以做成通用的,倒时候把脚本复制一下就行。

Animator包含一个动画状态机,本身可以实现非常复杂的功能。不过大多数情况也用不上。我这为了减少工作量,就约定了两个动画名"ShowAnim""HideAnim",然后在游戏的主要UI容器类上提供了SetActive(bl)方法,创建或者显示的时候播放容器下所有Animator的ShowAnim动画,关闭和隐藏的时候要求调用SetActive(false),这时候就会先播放所有Animator的HideAnim然后在播放完后隐藏界面,第一次SetActive(true)则是自动的,对技术人员而言也算隐藏的比较好。

由于界面可能分层,那Animator就可能在各层都存在一个实例。获取容器下所有Animator就能同时启动所有动画(一般主动播放的都是隐藏动画),大部分情况也可以兼容,就不用一个一个处理不同情况的动画分支了。子界面之间的切换和父级界面之间的切换都可以用同一个动画,处于不同状态的界面也都可以正常退出。

大部分情况,HideAnim就是ShowAnim的倒序播放,不用重建动画,复制ShowAnim然后将速度设为-1就可以,也可以适当加速。

动画是可以在功能完成后再添加的,也可以在运行时编辑,只要操作可回溯调整起来很方便。不运行的时候也可以预览和编辑。所以不管任何时候都是比DoTween更优越的。

缺陷是不能处理动态目标的动画,比如游标移动。但这种情况非常少见。

设计一个通用的模板

切换动画基本是由各个部分的显示/消隐组成的,目地是要用动画将不同界面连接起来。由于并不打算花费太大精力,一般的界面都遵循着通用的规律。分两种:1.先播放前一个界面的隐藏,再播放后一个界面的出现;2.同时播放前一个界面的隐藏和后一个界面的出现。后者很简单,就是普通的同时调用前一个界面的SetActive(false)和后一个界面的SetActive(true),前者就需要写个通用工具类来自动监听事件,或者包装在通用的视图管理类里。

每个单独分页里,各级界面的关系链比较单一,甚至是一对一的,这时候的动画就比较好处理,只靠显隐控制就够了。但是在多个分页之间,由于每个分页风格迥异,并且连背景图都不同,随便叠加很容易出现预期外的结果,所以选择先播放前一个界面的消失,再播放下个界面的出现的方案。中间的背景过渡采用截屏的方式用一个短透明度过渡来处理。

7b9762860154c241b6e5b5f95b949e09.gif

c517693fcf7af4e40f620a3e212afc31.png

然后再处理下列表项动画的播放,差不多就能达到一个及格标准了。

列表项动画仅仅实现很简单,在重复列表项的预制上挂上Animator就可以,但列表项是需要一定间隔顺序显示的,数量也不固定,属于动态内容,就需要用通用代码管理。

这里就一步到位,把列表项复制的过程也和动画一样做了延迟,这样复制列表项的成本就分摊到了多帧上,即使有复杂列表项也不会卡在初始化上。在一个循环列表上做这样的处理其实是有一定困难的,尤其是在生成列表项的同时还允许滚动的前提下。所以嫌麻烦也可以选择在这个时候锁定输入。

此外,因为在不少游戏里(比如刺客信条奥德赛),它们都采取了滚动时列表项渐显的做法,就像下面这种:

89dfa66fbe71f8e5c6e37599b37494c4.gif

97bb7a7b495292d76938d6a55942c27a.png

这样做可以一定程度缓解列表项边缘区域过硬的问题,但我觉还有个作用是给列表项里的图标预留加载时间,实际上这里的动画是预留了几帧完全透明的状态的,足够一般的图标完成加载。

此外,咱这游戏其实只是做了最小限定的动画内容,基本上还是怎么方便怎么来,曲线一般也都得是默认的,毕竟人力有限,也没有这方面的竞品对比压力。但即使是复杂的动画,也都是基于这种做法。大家可以去试图拆分其他游戏里看到的特殊转场,很大概率都可以拆解成不同界面的显示/隐藏动画连接,看起来连接着的部分其实两个界面把同样的元素恰好摆在同一个位置,然后在过渡的时候硬切。

具体的动画用多层Mask和形变就可以实现,虽然性能较差,但也不在乎这点吧。而这就是一个纯美术问题了。

但如果你以前做过Flash那个时代的交互动画……其实也没有看上去那么困难,就算是随便试验下也有概率出不错的效果的,想要做到“比没有好”还是比较容易的。

用动画来掩饰加载延迟

正如同刚才所说的,动画有时候不光是一种表现,同时也是一种化解卡顿感的手段。在缺乏常态动画存在的界面里,是可以在用户点击后再同步加载相关内容,短暂的卡死只会被视为触屏延时,但一旦存在循环动画就会露馅了。

除了在空闲期后台加载下个界面外,还有个技巧便是,你可以在上个界面的隐藏动画开始的时候就加载下个界面,隐藏动画虽然时间很短,但也足够掩盖下个界面的加载时间,毕竟这是将一帧的时长限制扩充到了原本的十几倍。界面也可以拆分成多部分,然后各部分次序渐显显示,同样也能争取到很多时间。这样动画虽然浪费了时间,但有很大一部分是加载时间,也就不算亏。

这不仅仅可以用在ui加载上,同时也可以用在场景加载上。在显示大块内容前先用一个较长的动画拖下时间,并在动画时间内加载,就可以略去,或者缩短传统的loading流程。比如一个正常的战斗模块加载,总时长可能也就7,8秒,你先用一个2秒的入场特效动画拖一下,把场景加载出来,显示场景后特效隐藏的时机里等待我方人物加载,播放人物的入场动画,接着再用一个battle start的文字动画拖时间,把敌方人物的资源加载完,正式开战的时机其实和以前差不多,但是等待的焦灼感会削弱很多。实际上,玩家在意的不是等待,而是打断。把等待时间转变成一个动画过程,等待过程似乎就被消除了。游戏里常见的开门侧身过墙钻洞都是这样的设计。

战斗入场特效最初的目的也是这个,只是不知国内厂商是不是这样做的。如果是等全部加载完再老老实实播放个纯耗时间的特效,或者播完特效再开始加载,就实在有些浪费了。

战斗结束的结算动画也可以作为回归初始界面的加载准备。

动画的功能性

UI动画并不是个花架子,它本身也可以给予用户额外提示,并且有辅助教学的作用。

最基本的规则是,变化的部分是动的,不变的地方是不动的。

具体动画的代表含义,APP领域,交互设计讲的够多了。游戏UI也是UI的一部分,并不特殊。果粉整天吹嘘的非线性动画,也是其中微不足道的一项。

好在APP那边已经完成了攻城略地,多半不会再有人去争论UI动画存在的必要性,而且资料也满多的。我因为以前是做社交平台应用的,那边的风气都是要将UI动画做到极致,所以在我眼里这一直都是理所当然的事,当时IPhone都还在娘胎里。

总之,动画大部分时候不是为了美观,而是具有特定的功能的。没有功能的动画要尽量少做,和功能相悖的动画原则上则是不能做的。

以下就是比较标准的例子,如果没有动画,用户甚至都无法理解自己的操作产生了什么样的结果。

7b9762860154c241b6e5b5f95b949e09.gif

90253abd5c07968a9b2dbe31318674d6.gif

而且动画本身带来的激励效果本身也是奖励的一部分。明明投放了收益,却没有让用户察觉,是非常蠢的。

技术人员或许会对第二张图里的图标归位感兴趣。这个列表虽然是个循环列表,每个数据对应的GameObject都是不固定的,但是它们所在的位置却是固定的。所以在删除格子前先记录每个数据对应的位置,然后完整刷新列表重新生成所有GameObject,再根据之前记录的位置把格子移到原本的位置,接着播放一次移动到当前位置的动画。这样原本不在区域内的格子也就能显示出来了。

动画的时长

为了不让动画招致反感,动画的时长必须要短。

大部分情况下,动画并不是目的,而是为了达成对应的功能。长时长的动画表达重要的行为,短时长的动画表达不重要的行为,而这个长短则是相对的。

所以,在用户很够看清的前提下,动画时长应该能短则短。

我一般的设置是:长时长0.5秒,中等时长0.25秒,短时长0.1秒。当然,要根据实际情况波动。

长时长动画是少见的,所以大部分动画都在0.25秒左右。而0.25秒也差不多是人类的极限反应时间,等到他们反应过来的时候动画已经播完了,就不会嫌弃动画阻碍他们的操作了。

然而在动画时长如此短的情况下,如果基础帧率只有30,那么整个动画就只有7.5帧,考虑到前后还有加减速的过程,中间快速移动部分的将会更快,每帧移动的位置就会更大,也就会产生很强烈的画面跳帧的感觉,也就是卡顿。所以想要使用这个数值,帧率达到60是很有必要的。或者就要重新设置动画曲线,让它中间的速度降低一些,但这样一来好好的非线性动画也就没了。

动态模糊理论上也能解决这个问题,但是哪可能用?

所以,60FPS对于UI动画来讲非常重要,可以的话还是要尽量达到,这就对其他地方的性能有了更高的要求。如果不能达到,就只能减慢动画速度一倍,或者减少大幅度的位移来回避这个问题。

3D方面

使用3DUI可以提升画面的纵深感,让画面的线条更加多样,避免死板。

3DUI遇到的第一个问题就是边缘锯齿,这个问题在斜线上也同样存在。解决方案是在贴图外圈预留一像素透明边,效果和传统反锯齿的结果很类似。所以UI不需要依赖反锯齿功能的。

UI通常不开启mipMap,这是因为UI通常并不会出现高倍率的图片缩放,3D界面为了维持可用性倾角也很小。但如果确实出现了线条走样问题,就需要开启mipMap。

UGUI对3DUI的支持非常糟糕,它的自动更改显示顺序合批的功能在3D界面中会失效,但是相邻的UI组件依然可以按材质合批,如果打好图集还是能处理掉很多Pass的。一个界面通常除了图标都处于同一个图集里,只有文本使用不同材质,所以只要把文本和非文本分开就能解决大部分的合批失效问题。所以可以用脚本始终同步文本的位置,让他们相对于背景移动,而不是依赖原本的父子级关系。

其他方案也不是没有,但都很麻烦。

这可以算是UGUI一个非常严重的缺陷,多半是因为使用3DUI的游戏过少的原因。其他开源或者支持手动设置depth的UI系统就没这问题。但是如果不使用UGUI,性能又不足以在界面动画中保持帧率,会更加得不偿失。至少,UGUI的问题还是可以花力气解决的,只要保证Pass数量不要超过战斗中的平均值,都还在可接受的范畴内。

实现上的困难

根本问题在于,国内的大部分UI设计师其实根本就不懂UI动画。

美术也是同样是分类别的,跨类别的时候,不懂就是不懂。所以即使硬让他们设计也设计不出来。他们不能的话,其他人也同样不能。简而言之,就是公司没有符合要求的人,公司也不认为应该招募和培养这样的人。

当然,不懂也可以现学。初学者无非就是做的不好,但是要做到比没有好,并不困难。

但是并不会做的。因为以前没有这样做,现在也不会这样做。因为以前都是程序拼界面,所以现在也是程序拼界面,即使现在从任何一个角度都找不到一丁点这样安排的合理性。

但这样安排,就是做不出来。即使做出来,付出的成本和代价也很高。

UI动画本身是非常简单的,但是没有专业的人来做,再简单的东西都会变得很困难。现在常态的做法就是美术/策划提需求,然后技术实现。但动画本身也是美术的一种,是需要通过试错来逼近最优解的,这样做根本无法进行多次迭代,效果自然不会好。而提需求的成本也会导致需求量降低。

所以问题就两个:

1.没有会做UI动画的人。

2.即使有,因为流程完全错误,耗时多,效果差。

所以我们需要先找一个会做UI动画的人(愿意自己学着做的也行),然后教会他如何使用Animator,告诉他和功能相关的约定,并把他插入到拼界面的流程后面去。

这只能解决通用UI动画的问题。遇到不通用的,则需要他和技术商量解决方案。

但还有一种情况是这样也解决不了的:并不是所有的动画都可以用Animator实现,这样美术就很难参与到迭代流程里,需要在技术之间来回打转耗费大量时间,难产的概率就会非常高。

这里就需要专长UI动画的TA上场,但在TA的定义都被扭曲的不成样子的现在,提这个似乎也没有什么意义。

但是没有就是做不出来,想做出来就必须有,归根结底还是看需求的紧迫性了,国内市场显然一点都不紧迫。

声明:发布此文是出于传递更多知识以供交流学习之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与我们联系,我们将及时更正、删除,谢谢。

作者:flashyiyi

来源:https://zhuanlan.zhihu.com/p/79915435

More:【微信公众号】 u3dnotes

dd91bf2994c6e2e8504465afd97825ff.png

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值