laya 播放ui中的动画_了解UI动画中的线性插值

laya 播放ui中的动画

by Nash Vail

由Nash Vail

了解UI动画中的线性插值 (Understanding Linear Interpolation in UI Animation)

In traditional (hand-drawn) animation, a senior or key artist draws keyframes that define the motion.

在传统(手绘)动画中,资深或关键美术师绘制定义动作的关键帧。

An assistant, generally an intern or a junior artist, then draws the necessary inbetweens for the scene. The job of the assistant, also called an inbetweener, is to make transitions between key poses look smooth and natural.

然后,通常是实习生或初级画家的助手会为场景绘制必要的中间。 助手(也称为中间人)的工作是使关键姿势之间的过渡看起来平滑自然。

Inbetweens are necessary since animations without them appear choppy. Unfortunately, drawing in-betweens is more or less grunt work. But it’s the twenty-first century, and we have computers that can handle this type of task.

间隔是必要的,因为没有它们的动画会显得不稳定。 不幸的是,介于两者之间是一项艰巨的工作。 但这是二十一世纪,我们拥有可以处理此类任务的计算机。

Remember what teachers told you in grade school about computers being dumb? Computers need to be told the exact sequence of steps to perform an action. Today we’ll look at one such sequence of steps, or algorithm, that helps the computer draw necessary inbetweens to create a smooth animation.

还记得老师在小学时告诉您的关于计算机愚蠢的事情吗? 需要告知计算机执行操作的确切步骤顺序。 今天,我们将研究一种这样的步骤或算法序列,这些序列或算法可帮助计算机绘制必要的中间内容以创建平滑的动画。

I’ll be using HTML5 canvas and JavaScript to illustrate the algorithm. However, you’ll be able to read and understand the article even if you aren’t familiar with them.

我将使用HTML5 canvas和JavaScript来说明该算法。 但是,即使您不熟悉它们,也可以阅读和理解该文章。

意图 (Intent)

Our goal is simple, to animate a ball from point A(startX, startY) to B (endX, endY).

我们的目标很简单,就是对从点A (startX, startY)到B (endX, endY)的球进行动画处理。

If this scene were passed to a studio that does traditional animation, the senior artist would draw the following key poses…

如果将此场景传递给执行传统动画的工作室,则高级艺术家将绘制以下关键姿势……

…and then pass the drawing board to a junior artist to draw inbetweens like so.

…然后将绘图板传递给初级艺术家,以进行中间绘制。

For our situation, there is no animation studio nor do we have junior artists. All we have is a goal, a computer, and the ability to write some code.

对于我们的情况,没有动画工作室,也没有初级艺术家。 我们所拥有的只是一个目标,一台计算机和编写某些代码的能力。

方法 (Approach)

The HTML code is simple, we only need one line.

HTML代码很简单,我们只需要一行。

<canvas id=”canvas”></canvas>

This part of the JavaScript code (shown below) simply grabs <canvas/> from the Document Object Model (DOM), gets context, and sets the width and height property of the canvas to match the viewport.

这部分JavaScript代码(如下所示) <canva文档对象模型(DOM)中gets c <canva s />, gets c文本,并设置画布的width和height属性以匹配视口。

const canvas = document.getElementById(‘canvas’),  context = canvas.getContext(‘2d’),  width = canvas.width = window.innerWidth,  height = canvas.height = window.innerHeight;

The function below draws a green solid circle of radius radius at x and y coordinates.

下面的函数在xy坐标处绘制半径为radius的绿色实心圆。

function drawBall(x, y, radius) {  context.beginPath();   context.fillStyle = ‘#66DA79’;  context.arc(x, y, radius, 0, 2 * Math.PI, false);  context.fill();}

All of the above code is boilerplate to set up our animation, here’s the juicy part.

以上所有代码都是用于设置动画的样板,这是多汁的部分。

// Point Alet startX = 50, startY = 50;
// Point Blet endX = 420, endY = 380;
let x = startX, y = startY;
update();function update() {  context.clearRect(0, 0, width, height);  drawBall(x, y, 30);  requestAnimationFrame(update);}

First of all, notice the update function being called right above its declaration. Second of all, notice requestAnimationFrame(update) which calls update repeatedly.

首先,请注意update函数在其声明上方被调用。 其次,注意requestAnimationFrame(update) ,它反复调用update

Flipbook animation is a good analogy for the kind of program we’re writing. Just like repeatedly flipping through a flipbook creates the illusion of motion, repeatedly calling the update function creates the illusion of motion for our green ball.

动画书动画是我们正在编写的程序的一个很好的类比。 就像反复翻动一本动画书会产生运动的错觉一样,反复调用update功能也会为我们的绿球产生运动的错觉。

One thing to note about the code above is that “update” is just a name. The function could have been named anything else. Some programmers like the names nextFrame, loop, draw, or flip because the function is repeatedly called. The important part is what the function does.

关于上述代码,需要注意的一件事是“更新”只是一个名称。 该函数可以被命名为其他任何名称。 一些程序员喜欢名称nextFrameloopdrawflip因为该函数被反复调用。 重要的部分是函数的功能。

On each subsequent call of update, we expect the function to draw a slightly different image on the canvas than the previous one.

在随后的每次update调用中,我们期望该函数在画布上绘制的图像与上一个图像略有不同。

Our current implementation of update draws the ball at the same exact position on each call drawBall(x, y, 30). There is no animation, but let’s change that. Below is a pen that contains the code we have written so far, you can open it and follow along.

我们当前的update实现在每个调用drawBall(x, y, 30)上的相同精确位置绘制球。 没有动画,但让我们对其进行更改。 下面是一支 ,其中包含我们到目前为止已编写的代码,您可以打开它并继续学习。

On each iteration of update let’s go ahead and increment the value of x and y and see the kind of animation it creates.

在每次update的迭代中,让我们继续增加xy的值,并查看其创建的动画类型。

function update() {  context.clearRect(0, 0, width, height);  drawBall(x, y, 30);  x++; y++;  requestAnimationFrame(update);}

Each iteration moves the ball forward in both the x and y directions, and repeated calls of update results in the animation as shown.

每次迭代都将球沿x和y方向向前移动,并在动画中反复调用update结果,如图所示。

Heres’ the deal though, our intent was to move the ball from a start position to an end position. But we’re doing absolutely nothing about stopping the ball at an end position. Let’s fix that.

不过,这是交易,我们的目的是将球从起始位置移动到结束位置 。 但是我们绝对没有将球停在终点位置。 让我们修复它。

One obvious solution is to only increment the coordinates when they are smaller than endX and endY values. This way, once the ball crosses endX, endY its coordinates will stop updating and the ball will stop.

一种明显的解决方案是仅在坐标小于endXendY值时增加坐标。 这样,一旦球越过endX, endY其坐标将停止更新,并且球将停止。

function update() {  context.clearRect(0, 0, width, height);  drawBall(x, y, 30);   if(x <= endX && y <= endY) {    x++;    y++;  }   requestAnimationFrame(update);}

There’s an error in this approach though. Do you see it?

但是这种方法有一个错误。 你看到了吗?

The problem here is that you cannot make the ball reach any end coordinate you want just by incrementing x and y values by 1. For example, consider end coordinates (500, 500), of course if you start at (0, 0) and add 1 to x and y, they will eventually get to(500, 500). But what if I chose (432, 373) as end coordinates?

这里的问题是,仅通过将xy值增加1 ,就无法使球达到所需的任何终点坐标。 例如,考虑结束坐标(500, 500) ,当然,如果您从(0, 0)并将xy1 ,则它们最终将达到(500, 500) 。 但是,如果我选择(432, 373)作为结束坐标怎么办?

Using the above approach, you can only reach points lying in a straight line 45 degrees from the horizontal axis.

使用上述方法,您只能到达与水平轴成45度的直线上的点。

Now you can use trigonometry and fancy math to calculate precise amounts that x and y should be incremented by to reach any coordinate you want. But you don’t need to do that when you have linear interpolation.

现在,您可以使用三角函数和奇特数学来计算xy递增所需的精确量,以达到所需的任何坐标。 但是,当您进行线性插值时,不需要这样做。

线性插值法 (Approach with linear interpolation)

Here’s what linear interpolation function a.k.a lerp looks like.

这就是线性插值函数(即lerp样子。

function lerp(min, max, fraction) {  return (max — min) * fraction + min;}

To understand what linear interpolation does, consider a slider with a min value on the left end and a max value on the right end.

要了解线性插值的作用,请考虑一个滑块,其min在左端, max在右端。

The next thing we need to choose is fraction. lerp takes fraction and converts that to a value between min and max.

接下来需要选择的是fractionlerpfraction并将其转换为minmax之间的值。

When I put 0.5 in the lerp formula — no surprises — it translates to 50. This is exactly the halfway point between 0 (min) and 100 (max).

当我在lerp公式中输入0.5时(毫无意外),它转换为50。这恰好是0 (最小)和100 (最大)之间的中间点。

Similarly, if we choose another value for fraction say 0.85

同样,如果我们为fraction选择另一个值,请说0.85

And if we let fraction = 0, lerp will output 0 (min) and on fraction = 1, lerp will produce 100 (max).

如果我们让fraction = 0 ,则lerp将输出0 (最小值),而当fraction = 1lerp将产生100 (最大值)。

I chose 0 and 100 as min and max to keep this example simple, but lerp will work for any arbitrary choice of min and max.

为了使本示例简单,我选择了0和100作为minmax ,但是lerp适用于minmax任意选择。

For values of fraction between 0 and 1, lerp allows you to interpolate between min and max. Or in other words, traverse between min and max values, where choosing 0 for fraction puts you at min, choosing 1 puts you at max and for any other value between 0 and 1, puts you anywhere between min and max. You can also see min and max as key poses, like in traditional animation, and lerp outputs as inbetweens ;-).

对于介于01之间的fraction值, lerp允许您在minmax之间进行插值 。 换句话说,在minmax之间移动,对于fraction选择0将使您处于min ,对于fraction选择1将使您处于max ,对于介于01之间的任何其他值,将您置于minmax之间。 您还可以将minmax作为关键姿势,如在传统动画中一样,将lerp输出作为中间的;-)。

Alright, but what if someone gives a value outside the bounds of 0 and 1 as fraction to lerp? You see the formula for lerp is extremely straightforward with most basic of mathematical operations. There’s no trick or bad values here, just imagine extending the slider in both directions. Whatever value for fraction is supplied, lerp will produce a logical result. We shouldn’t pay much thought to bad values here though, what we should think about is how all of this maps to animating the ball.

好的,但是如果有人给出01之外的值作为lerp fractionlerp怎么lerp ? 您会看到lerp的公式非常简单,具有最基本的数学运算功能。 这里没有技巧或错误的值,只需想象一下向两个方向延伸滑块即可。 无论提供什么fraction值, lerp 都会产生逻辑结果。 但是,我们不应该在这里考虑糟糕的值,我们应该考虑的是所有这些如何映射到动画上。

If you’re following along go ahead and change the update function to match the following code. Also don’t forget to add in the lerp function we defined at the beginning of this section.

如果您继续进行,请更改update功能以匹配以下代码。 同样不要忘记添加在本节开头定义的lerp函数。

function update() {  context.clearRect(0, 0, width, height);  drawBall(x, y, 30);  x = lerp(x, endX, 0.1);  y = lerp(y, endY, 0.1);  requestAnimationFrame(update);}

Here’s a pen of what our program looks like now. Try clicking around :)

这里有一个的什么我们的程序看起来像现在这样。 尝试点击:)

Smooth right? Here’s how lerp helps to improve the animation.

顺利吧? 以下是lerp如何帮助改善动画的方法。

In the code, notice the variables x and y — which are initially set to startX and startY— mark the current position of the ball in any frame. Also my choice of 0.1 as fraction is arbitrary, you can choose any fractional value you want. Keep in mind that your choice of fraction affects the speed of the animation.

在代码中,请注意变量xy (最初设置为startXstartY在任何框架中标记了球的当前位置。 同样,我选择0.1作为fraction是任意的,您可以选择任何想要的分数值。 请记住, fraction的选择会影响动画的速度。

In every frame x and endX are taken as min and max and interpolated with 0.1 as fraction to obtain a new value forx. Similarly y and endY are used as min and max to obtain a new value for y using 0.1 as fraction.

在每一帧中, xendX分别取作minmax并以0.1作为fraction进行插值以获得x的新值。 类似地,将yendY用作minmax0.1为分数获得y的新值。

The ball is then drawn at the newly calculated(x, y) coordinate.

然后在新计算的(x, y)坐标处绘制球。

These steps are repeated until x becomes endX and y becomes endY in which case min = max. When min and max become equal lerp throws the exact same value(min/max) for any further frames thus stopping the animation.

重复这些步骤,直到x变为endXy变为endY为止,在这种情况下min = max 。 当minmax变得相等时, lerp将为任何其他帧抛出完全相同的值(min / max),从而停止动画。

And that is how you use linear interpolation to smoothly animate a ball.

这就是使用线性插值平滑地对球进行动画处理的方式。

This short article covers a lot. We started by defining terms like key poses and inbetweens. Then we tried a trivial approach for drawing inbetweens and noticed its limitations. Finally, with linear interpolation, we were able to achieve our intent.

这篇简短的文章涵盖了很多。 我们首先定义关键姿势和中间词等术语。 然后,我们尝试了一种简单的方法来绘制中间对象,并注意到了它的局限性。 最后,通过线性插值,我们能够实现我们的目的。

I hope all the math made sense to you. Feel free to play with linear interpolation even more. This article was inspired by Rachel Smith’s post on CodePen. Rachel’s post has many more examples, be sure to check it out.

我希望所有数学对您来说都是有意义的。 随意使用线性插值,甚至更多。 本文的灵感来自Rachel Smith 在CodePen上的帖子 。 Rachel的帖子还有更多示例,请务必查看。

Looking for more? I publish regularly on my blog at nashvail.me. See you there, have a good one!

寻找更多? 我定期在我的博客nashvail.me上发布 到那里见,祝你好运!

翻译自: https://www.freecodecamp.org/news/understanding-linear-interpolation-in-ui-animations-74701eb9957c/

laya 播放ui中的动画

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值