热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在Unity引擎中使用EasingFunction制作动画

在制作游戏的时候,动画是不可或缺的一部份,即使是与游戏核心无关的GUI部份,若少了动画就显得粗制滥造。然而大多数的GUI效果:

在制作游戏的时候,动画是不可或缺的一部份,即使是与游戏核心无关的 GUI 部份,若少了动画就显得粗制滥造。然而大多数的 GUI 效果:像是视窗飞进画面中央、按下按钮时放大效果之类的动画等等,其内容都有很高的相似性,也就是「在某段时间内,把物件的某些状态转移到另一个状态」。若要使用 3D Max 之类的软件一一制作,将显得麻烦而没有效率。

在这篇文章中,以 Unity 作为范例,介绍如何实作一个简单的 easing function 元件。

范例需求

想像一下我们正在制作游戏过程中的暂停按钮。当玩家按下暂停钮时,画面上会出现暂停的面板以及三个按钮。当然,直接让它们出现是很粗糙的作法,因此我们希望面板及按钮可以从画面外飞进来。

使用线性内插

最简单的呈现方式是使用线性内插法,指定好某个物件的起始状态(位置、大小、顏色等)与结束状态,再指定动画时间。只要有了这些资讯,我们可以用简单的数学运算内插出动画播放时每一格 frame 的物件状态。




01

using UnityEngine;

02

using System;

03


04

public class EasingDemo : MonoBehaviour {

05

public Vector3 destination;

06

public float duration = 1;

07

public float delay = 0;

08


09

private Vector3 source;

10

private Vector3 delta;

11

private float elapsed = 0;

12


13

void Start()

14

{

15

source = transform.position;

16

delta = destination − source;

17

}

18


19

void Update()

20

{

21

elapsed += Time.deltaTime;

22

if(elapsed > delay && elapsed < (delay+duration)){

23

float ratio = Math.Min(1, (elapsed&minus;delay)/duration);

24

transform.position = source + ratio*delta;

25

}

26

}

27

}

这个简单的元件让我们可以在 Unity 编辑器中直接设定物件的起始位置、结束位置及动画播放的时间。接下来,我们把面板与按钮放在镜头外面,然后把它的结束位置设定在画面内,按下 play 后马上可以看到它的效果……

这个动画之所以看起来很无聊,大部份的原因在于我们使用了很无聊的线性内插法。想像一下如果这个按钮是用以下的方式飞进画面:


  1. 很快地冲进来,然后紧急剎车停在目的地。
  2. 冲过头然后拉回目的地。
  3. 撞到目的地后像皮球般反弹,最后再落回目的地。

这样的动画,显然会比死板的等速度飞入更活泼、更有动感。然而制作这种动画效果就没办法用线性内插了。当然,若使用 3D Max 就可以借由贝兹曲线 (Bézier curve) 来编辑这种较复杂的动画,或是直接用 Unity 的动画编辑器也能办到。然而编辑贝玆曲线的各个控制点却是一件很花时间的工作,尤其像第三个例子,为了达到反弹的效果,我们得额外加入两三个 key frame 才行。过程并不是很难,但就是很花时间。

正在上传…重新上传取消

Unity 使用 Easing Function 制作动画

使用非线性内插法

我们不希望动画是平板的线性内插法,但又觉得编辑贝兹曲线的控制点太麻烦,那么答案就呼之欲出了:使用其它的数学曲线来代替直线。比如说如下的曲线:

正在上传…重新上传取消

在Unity引擎中使用Easing Function制作动画

尽管物理上并不正确,但它看起来就像是「很快地冲进来,然后紧急剎车」的样子。因此我们可以把它套用到内插计算式中:




1

void Update()

2

{

3

elapsed += Time.deltaTime;

4

if(elapsed > delay && elapsed < (delay+duration)){

5

float x = Math.Min(1, (elapsed&minus;delay)/duration);

6

float ratio = (float)Math.Pow(x&minus;1, 3) + 1;

7

transform.position = source + ratio*delta;

8

}

9

}

结果如下,同样都是一秒钟的动画,感觉起来是不是有微妙的差异呢?

Easing Function 惯例格式

Easing function 具有一项优势:只要抽换不同的 easing function,不需要另外编辑 key frame 或是曲线控制点,就马上可以得到另一种动画。但为了达到这个「可抽换」的目的,我们得要使用大家所惯用的写法:




01

public class Easing {

02

public static float Linear(float t, float b, float c, float d)

03

{

04

return c*(t/d) + b;

05

}

06


07

public static float OutCubic(float t, float b, float c, float d)

08

{

09

t /= d;

10

t&minus;&minus;;

11

return c*(t*t*t+1)+b;

12

}

13

}

一般化的 easing function 有四个参数:


  1. t (time): 代表动画开始播放到现在所经过的时间。
  2. b (beginning): 代表某项属性的初始值。
  3. c (change): 代表到动画结束时,该属性的变化值。亦即动画结束后,这项属性的值应為 b+c。
  4. d (duration): 代表整段动画的播放时间。

因此我们可以改写原本的 Update():




01

public delegate float EasingFunction(float t, float b, float c, float d);

02

EasingFunction easing = new EasingFunction(Easing.OutCubic);

03


04

void Update()

05

{

06

elapsed += Time.deltaTime;

07

if(elapsed > delay && elapsed < (delay+duration)){

08

Vector3 p = new Vector3();

09

float t = elapsed &minus; delay;

10

p.x = easing(t, source.x, delta.x, duration);

11

p.y = easing(t, source.y, delta.y, duration);

12

p.z = easing(t, source.z, delta.z, duration);

13

transform.position = p;

14

}

15

}

这么一来,我们就可以利用别人写好的 easing function 套用到我们的动画元件中。事不迟疑,马上就来看看范例。

弹跳动画

上述「像是皮球般地弹跳」显然是一种很困难的曲线,但早就有人写好了它的 easing function,只要 google 一下马上就能找到如下的程式码:


public static float Bounce(float t, float b, float c, float d)
02{
03if ((t /= d) <(1.0f / 2.75)) {
04return c * (7.5625f * t * t) + b;
05}
06else if (t <(2.0f / 2.75)) {
07return c * (7.5625f * (t−=(1.5f/2.75f)) * t + 0.75f) + b;
08}
09else if (t <(2.5f / 2.75)) {
10return c * (7.5625f * (t−=(2.25f/2.75f)) * t + 0.9375f) + b;
11}
12else {
13return c * (7.5625f * (t−=(2.625f/2.75f)) * t + 0.984375f) + b;
14}
15}

然后我们把 EasingDemo 中的 easing function 设定为 Easing.Bounce,马上就能看到弹跳的面板与按钮:

这样的效果是不是比前面慢慢飞进来的动画要生动许多呢?

只要指定起始状态、结束状态、播放时间及 easing function 的种类,即可组合出千变万化的各种效果,因此 easing function 是相当广泛的 2D 动画技术。知名的 Javascript 函式库 jQuery 也内建了许多不同种类的 easing function。

Unity 范例场景可以在 这边 下载。可导入Unity看到范例程式码及实际的动画效果。


推荐阅读
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
  • 本文介绍了如何使用n3-charts绘制以日期为x轴的数据,并提供了相应的代码示例。通过设置x轴的类型为日期,可以实现对日期数据的正确显示和处理。同时,还介绍了如何设置y轴的类型和其他相关参数。通过本文的学习,读者可以掌握使用n3-charts绘制日期数据的方法。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 深度学习中的Vision Transformer (ViT)详解
    本文详细介绍了深度学习中的Vision Transformer (ViT)方法。首先介绍了相关工作和ViT的基本原理,包括图像块嵌入、可学习的嵌入、位置嵌入和Transformer编码器等。接着讨论了ViT的张量维度变化、归纳偏置与混合架构、微调及更高分辨率等方面。最后给出了实验结果和相关代码的链接。本文的研究表明,对于CV任务,直接应用纯Transformer架构于图像块序列是可行的,无需依赖于卷积网络。 ... [详细]
  • 突破MIUI14限制,自定义胶囊图标、大图标样式,支持任意APP
    本文介绍了如何突破MIUI14的限制,实现自定义胶囊图标和大图标样式,并支持任意APP。需要一定的动手能力和主题设计师账号权限或者会主题pojie。详细步骤包括应用包名获取、素材制作和封包获取等。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • 合并列值-合并为一列问题需求:createtabletab(Aint,Bint,Cint)inserttabselect1,2,3unionallsel ... [详细]
  • GPT-3发布,动动手指就能自动生成代码的神器来了!
    近日,OpenAI发布了最新的NLP模型GPT-3,该模型在GitHub趋势榜上名列前茅。GPT-3使用的数据集容量达到45TB,参数个数高达1750亿,训练好的模型需要700G的硬盘空间来存储。一位开发者根据GPT-3模型上线了一个名为debuid的网站,用户只需用英语描述需求,前端代码就能自动生成。这个神奇的功能让许多程序员感到惊讶。去年,OpenAI在与世界冠军OG战队的表演赛中展示了他们的强化学习模型,在限定条件下以2:0完胜人类冠军。 ... [详细]
  • 本文讨论了如何使用GStreamer来删除H264格式视频文件中的中间部分,而不需要进行重编码。作者提出了使用gst_element_seek(...)函数来实现这个目标的思路,并提到遇到了一个解决不了的BUG。文章还列举了8个解决方案,希望能够得到更好的思路。 ... [详细]
author-avatar
renminxilu662
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有