作者:vivo 互联网前端团队 - ZhaoJie
本文将从各个角度来对动画整个体系进行分类,并且介绍各种前端动画的实现办法,最初咱们将总结在理论开发中的各个场景的动画抉择计划。
一、背景
前端动画场景需要多
对泛滥动画场景的技术实现计划抉择上比拟含糊
各动画计划的优劣及实用场景意识含糊
现有动画库太多,不晓得选哪个
支流动画库的实用场景意识含糊
上面首先让咱们从各个角度来对动画整个体系进行分类,让咱们清晰的理解动画整个体系。
二、分类
2.1 用处角度
首先咱们从动画的用处或者说是业务的角度来进行辨别,将咱们平时的动画分为展现型动画和交互型动画。
2.1.1 展现型动画
相似于一张 GIF 图,或者一段视频。比方在开启宝箱的时候,咱们会退出一个切场过渡动画,来代替原有的僵硬期待后果。
展现型动画在理论应用的场景中,实现的办法很多,比方用 GIF 图,canvas,CSS3 动画等,然而最终输入的 后果是不带有交互的 ,也就是从动画起始状态到完结状态零打碎敲,这个过程 用户能够感知,然而无奈参加。
2.1.2 交互型动画
用户自已参加的,对于交互性动画而言,咱们能够在动画播放的某个工夫节点触发相应的操作,进而让用户参加到其中,最常见的例子 红包雨,不仅仅能晋升用户的体验,还能晋升咱们的产品的多元性。
然而交互性动画常常面临的一个问题就是,通过原生代码实现交互动画是很简单的,同时性能和兼容性是不得不认真思考的问题,比拟好的解决方案还是寻求相干的框架。
2.2 绘制技术角度
不论采纳什么形式来制作动画,最终出现到前端页面的无非是以下三种模式:
- Canvas
- div
- SVG
PS:为了简略也能够用视频,但除非动画的播放场景固定,不然挪动端视频在不同 app、不同机型、不同零碎的播放显示都不太一样,容易踩不少坑。
2.2.1 不同绘制技术的性能差别
Canvas
- 效率高、性能好、可控性高,只能解决位图,内存占用恒定
- 依赖分辨率
- 不反对事件处理器
- 弱的文本渲染能力
- 可能以 .png 或 .jpg 格局保留后果图像
- 最适宜图像密集型的游戏,其中的许多对象会被频繁重绘
div
- 包含 CSS 管制的 DOM 动画、JS 管制的 DOM 动画
- 比拟适宜简略的数量较少的复杂度较低的动画
SVG
- 解决矢量图,不失真
- 不依赖分辨率
- 反对事件处理器
- 最适宜带有大型渲染区域的应用程序(比方谷歌地图)
- 复杂度高会减慢渲染速度(任何适度应用 DOM 的利用都不快)
- 不适宜游戏利用
2.2.2 Canvas 和 SVG 比拟
一句话总结:都是 2D 做图,svg 是矢量图,canvas 是位图。canvas 是逐像素进行渲染的,适宜游戏。
SVG
- SVG 绘制的是矢量图,缩放不影响显示,所以最适宜带有大型渲染区域的应用程序(比方谷歌地图)
- SVG 是一种应用 XML 形容 2D 图形的语言。
- SVG 基于 XML,这意味着 SVG DOM 中的每个元素都是可用的。您能够为某个元素附加 JavaScript 事件处理器。
- 在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器可能主动重现图形。
Canvas
- Canvas 通过 JavaScript 来绘制 2D 图形。
- Canvas 是逐像素进行渲染的。
- 在 Canvas 中,一旦图形被绘制实现,它就不会持续失去浏览器的关注。如果其地位发生变化,那么整个场景也须要从新绘制,包含任何或者已被图形笼罩的对象。
- Canvas 只占用一个 DOM 节点,在做一些烟花、飘雪等静止元素很多的动画时,会比 CSS/SVG 性能好。
性能比拟
- 个别状况下,随着屏幕大小的增大,canvas 将开始降级,因为须要绘制更多的像素。
- 随着屏幕上的对象数目增多,SVG 将开始降级,因为咱们正一直将这些对象增加到 DOM 中。
- 这些度量不肯定精确,以下方面的不同肯定会引起变动:实现和平台、是否应用齐全硬件加速的图形,以及 JavaScript 引擎的速度。
2.3 动画类型角度
前端动效开发,首先应该确定的是
动画用处 -> 确认动画类型 -> 确认绘制技术 -> 确认动画的实现形式。
尽管最终出现动画的载体(绘制技术)就三种,但实现动画的形式却很多,得 从动画类型登程探讨动画的实现形式:
(1)逐帧动画(序列帧动画)
- GIF 实现
- CSS 实现(animation)
- JS+DOM 实现
- JS+canvas 实现
(2)补间动画(Tween 动画 \ 关键帧动画)
- CSS 实现(transition、animation 等)应用一些缓动函数
- JS 实现
(3)SVG 动画
- 应用 XML 格局定义图形
- 能够用 AI 等 SVG 编辑工具生成 SVG 图片后,配合 anime.js、GSAP 等现有库进行动画制作
(4)骨骼动画
- 个别采纳 Spine、DragonBones 等工具导出相应资源图片和 JSON 动画配置资源后应用。
(5)3D 动画
- DOM 操作用 CSS 3D 实现。(perspective 属性、css3d-engine)
- 场景搭建用 webGL(Three.js 等)
- 3D 模型动画用 Blender 或 maya 等制作实现后导出应用
2.3.1 逐帧动画(序列帧动画)
逐帧动画是在工夫帧上逐帧绘制帧内容,因为是一帧一帧的画,所以逐帧动画具备十分大的灵活性,简直能够体现任何想体现的内容。
因为逐帧动画的帧序列内容不一样,不仅减少制作累赘而且最终输入的文件量也很大,但它的劣势也很显著:因为它类似与电影播放模式,很适宜于表演很细腻的动画,如 3D 成果、人物或动物急剧转身等等成果。
所以逐帧动画的实现外围是什么,就是将咱们的这些动态的图片进行疾速的循环播放,造成了一个动静的动画成果。这就是帧动画。
2.3.1.1 GIF 实现
咱们能够将帧动画导出成 GIF 图,GIF 图会间断播放,无奈暂停,它往往用来实现小细节动画,老本较低、使用方便。但其毛病也是很显著的:
- 画质上,GIF 反对色彩少(最大 256 色)、Alpha 透明度反对差,图像锯齿毛边比较严重;
- 交互上,不能间接管制播放、暂停、播放次数,灵活性差;
- 性能上,GIF 会引起页面周期性的 绘画,性能较差。
2.3.1.2 CSS 实现
CSS3 帧动画是咱们明天须要重点介绍的计划,最外围的是利用 CSS3 中Animation 动画,确切的说是应用 animation-timing-function 的阶梯函数 steps(number\_of\_steps, direction) 来实现逐帧动画的间断播放。
帧动画的实现原理是一直切换视觉内图片内容,利用视觉滞留生理景象来实现间断播放的动画成果,上面咱们来介绍制作 CSS3 帧动画的几种计划。
(1)间断切换动画图片地址 src(不举荐)
咱们将图片放到元素的背景中(background-image),通过更改 background-image 的值实现帧的切换。然而这种形式会有以下几个毛病,所以该计划不举荐。
- 多张图片会带来多个 HTTP 申请
- 每张图片首次加载会造成图片切换时的闪动
- 不利于文件的治理
(2)间断切换雪碧图地位(举荐)咱们将所有的帧动画图片合并成一张雪碧图,通过扭转 background-position 的值来实现动画帧切换。分两步进行:
步骤一:
将动画帧合并为雪碧图,雪碧图的要求能够看下面 素材筹备,比方上面这张帧动画雪碧图,共 20 帧。
步骤二:
应用 steps 阶梯函数切换雪碧图地位
写法一:
<div class="sprite"></div>
.sprite {
width: 300px;
height: 300px;
background-repeat: no-repeat;
background-image: url(frame.png);
animation: frame 333ms steps(1,end) both infinite;
}
@keyframes frame {0% {background-position: 0 0;}
5% {background-position: -300px 0;}
10% {background-position: -600px 0;}
15% {background-position: -900px 0;}
20% {background-position: -1200px 0;}
25% {background-position: -1500px 0;}
30% {background-position: -1800px 0;}
35% {background-position: -2100px 0;}
40% {background-position: -2400px 0;}
45% {background-position: -2700px 0;}
50% {background-position: -3000px 0;}
55% {background-position: -3300px 0;}
60% {background-position: -3600px 0;}
65% {background-position: -3900px 0;}
70% {background-position: -4200px 0;}
75% {background-position: -4500px 0;}
80% {background-position: -4800px 0;}
85% {background-position: -5100px 0;}
90% {background-position: -5400px 0;}
95% {background-position: -5700px 0;}
100% {background-position: -6000px 0;}
}
针对以上动画有疑难?
问题一:既然都具体定义关键帧了,是不是能够不必 steps 函数了,间接定义 linear 变动不就好了吗?
animation: frame 10s linear both infinite;
如果咱们定义成这样,动画是不会阶梯状,一步一步执行的,而是会间断的变动背景图地位,是挪动的成果,而不是切换的成果,如下图:
问题二:不是应该设置为 20 步吗,怎么变成了 1?
这里咱们先来理解下 animation-timing-function 属性。CSS animation-timing-function 属性定义 CSS 动画在每一动画周期中执行的节奏。
综上咱们能够晓得,因为咱们具体定义了一个动画周期,也就是说 0% ~ 5% 之间变动一次,5% ~ 10% 变动一次,所以咱们这样写能力达到想要的成果。
写法二:
<div class="sprite"></div>.sprite { width: 300px;
height: 300px;
background-repeat: no-repeat;
background-image: url(frame.png);
animation: frame 333ms steps(20) both infinite;
}
@keyframes frame {0% {background-position: 0 0;}// 可省略
100% {background-position: -6000px 0;}
}
这里咱们定义了关键帧的开始和完结,也就是定义了一个关键帧周期,但因为咱们没有具体的定义每一帧的展现,所以咱们要将 0%~100% 这个区间分成 20 步来阶段性展现。
(3)间断挪动雪碧图地位(挪动端举荐)
跟第二种基本一致,只是切换雪碧图的地位过程换成了 transform:translate3d()来实现,不过要加多一层 overflow: hidden; 的容器包裹,这里咱们以只定义初始和完结帧为例,应用 transform 能够开启 GPU 减速,进步机器渲染成果,还能无效解决挪动端帧动画抖动的问题。
<div class="sprite-wp"> <div class="sprite"></div></div>
.sprite-wp {
width: 300px;
height: 300px;
overflow: hidden;
}
.sprite {
width: 6000px;
height: 300px;
will-change: transform;
background: url(frame.png) no-repeat center;
animation: frame 333ms steps(20) both infinite;
}
@keyframes frame {0% {transform: translate3d(0,0,0);}
100% {transform: translate3d(-6000px,0,0);}
}
steps() 函数详解
从下面的代码咱们能够发现,CSS 实现的外围就是应用 animation-timing-function 缓动函数的阶梯函数 steps(number\_of\_steps, direction)来实现逐帧动画的间断播放的。
接着咱们来理解下 steps() 函数:
steps 指定了一个阶梯函数,蕴含两个参数:
- 第一个参数指定了函数中的距离数量(必须是正整数);
- 第二个参数可选,指定在每个距离的终点或是起点产生阶跃变动,承受 start 和 end 两个值,默认为 end。
- start 第一帧是第一步动画的完结,end 第一帧是第一步动画的开始。
除了 steps 函数,animation-timing-function 还有两个与逐帧动画相干的属性值 step-start 与 step-end:
- step-start 等同于 steps(1,start)
- step-end 等同于 steps(1,end)
2.3.1.3 JS 实现
(1)通过 JS 来管制 img 的 src 属性切换(不举荐)
和下面 CSS3 帧动画外面切换元素 background-image 属性一样,会存在多个申请等问题,所以该计划咱们不举荐,然而这是一种解决思路。
(2)通过 JS 来管制 canvas 图像绘制
通过 canvas 制作帧动画的原理是用 drawImage 办法将图片绘制到 canvas 上,一直擦除和重绘就能失去咱们想要的成果。
<canvas id="canvas" width="300" height="300"></canvas>(function () { var timer = null,
canvas = document.getElementById("canvas"),
context = canvas.getContext('2d'),
img = new Image(),
width = 300,
height = 300,
k = 20,
i = 0;
img.src = "frame.png"; function drawImg() {context.clearRect(0, 0, width, height);
i++; if (i == k) {i = 0;}
context.drawImage(img, i * width, 0, width, height, 0, 0, width, height); window.requestAnimationFrame(drawImg);
}
img.onload = function () { window.requestAnimationFrame(drawImg);
}
})();
下面是通过扭转裁剪图像的 X 坐标地位来实现动画成果的,也能够通过扭转画布上搁置图像的坐标地位实现,如下:
context.drawImage(img, 0, 0, width*k, height,-i*width,0,width*k,height);
(3)通过 JS 来管制 CSS 属性值变动
这种形式和后面 CSS3 帧动画一样,有三种形式,一种是通过 JS 切换元素背景图片地址 background-image,一种是通过 JS 切换元素背景图片定位 background-position,最初一种是通过 JS 挪动元素 transform:translate3d(),第一种不做介绍,因为同样会存在多个申请等问题,不举荐应用,这里实现前面两种。
切换元素背景图片地位 background-position
.sprite { width: 300px;
height: 300px;
background: url(frame.png) no-repeat 0 0;
}
<div class="sprite" id="sprite"></div>(function(){var sprite = document.getElementById("sprite"),
picWidth = 300,
k = 20,
i = 0,
timer = null; // 重置背景图片地位
sprite.style = "background-position: 0 0"; // 扭转背景图地位
function changePosition(){sprite.style = "background-position:"+(-picWidth*i)+"px 0";
i++; if(i == k){i = 0;} window.requestAnimationFrame(changePosition);
} window.requestAnimationFrame(changePosition);
})();
挪动元素背景图片地位 transform:translate3d()
.sprite-wp { width: 300px;
height: 300px;
overflow: hidden;
}
.sprite { width: 6000px;
height: 300px;
will-change: transform;
background: url(frame.png) no-repeat center;
}
<div class="sprite-wp"> <div class="sprite" id="sprite"></div></div>
(function () {var sprite = document.getElementById("sprite"),
picWidth = 300,
k = 20,
i = 0,
timer = null;
// 重置背景图片地位
sprite.style = "transform: translate3d(0,0,0)";
// 扭转背景图挪动
function changePosition() {sprite.style = "transform: translate3d(" + (-picWidth * i) + "px,0,0)";
i++;
if (i == k) {i = 0;}
window.requestAnimationFrame(changePosition);
}
window.requestAnimationFrame(changePosition);
})();
2.3.1.4 性能剖析
咱们通过 Chrome 浏览器的各种工具,查看了每种计划的 FPS、CPU 占用率、GPU 占用、Scripting、Rendering、Painting、内存的应用状况,失去以下数据:
通过剖析以上数据咱们能够得出以下几点:
- 除了 CSS transform:translate3d() 计划,其余计划的 FPS 都能达到 60FPS 的晦涩水平,但该计划的 FPS 也不是很低。
- CPU 占用率最低的计划是
CSS transform:translate3d() 计划。 - GPU 占用最低的计划是 JS canvas 绘制计划。
- CSS 计划没有脚本开销。
- Rendering 起码的是
CSS transform:translate3d() 计划。 - Painting 起码的是
CSS transform:translate3d() 计划。 - 各计划内存占用区别不大。
论断:咱们看到,在 7 个指标中,CSS transform:translate3d() 计划将其中的 4 个指标做到了最低,从这点看,咱们齐全有理由抉择这种计划来实现 CSS 帧动画。
2.3.2 补间动画(Tween 动画 \ 关键帧动画)
补间动画是动画的根底模式之一,又叫做两头帧动画, 突变动画,指的是人为设定动画的要害状态,也就是关键帧,而关键帧之间的过渡过程只须要由计算机解决渲染的一种动画模式。
说白了,就是咱们在做动画的时候,只须要指定几个非凡时刻动画的状态,其余的状态由计算机主动计算补充。
实现补间动画常见的伎俩次要由以下几种:
- CSS3 Animation:通过 animation(除 steps()以外的工夫函数)属性在每个关键帧之间插入补间动画。
- CSS3 Transition:区别于 animation,transition 只能设定初始和完结时刻的两个关键帧状态。
- 利用 JavaScript 实现动画:例如 JavaScript 动画库或框架,Anime.js 或者 TweenJS,它是 CreateJS 的其中一个套件。另外,在 Flash 业界久负盛名的 GreenSock 推出的 GSAP(GreenSock Animation Platform)也新引入了对 Javascript 动画的反对。
2.3.2.1 CSS 实现
(1)transition 动画
transition 容许 CSS 的属性值在肯定的工夫区间内平滑地过渡,即指定元素的初始状态 和开端状态,既能够实现一个动画,两头的变动齐全有浏览器本人决定。动画的成果次要还是看 transition 相干属性即可。
然而利用 transition 制作的动画也有着显著的毛病:
- transition 须要事件触发,所以没法在网页加载时主动产生。
- transition 是一次性的,不能反复产生,除非一再触发。
- transition 只能定义开始状态和完结状态,不能定义中间状态,也就是说只有两个状态。
- 一条 transition 规定,只能定义一个属性的变动,不能波及多个属性。
(2)animation 动画
利用 animation 能够实现一个残缺的 CSS 补间动画,如下面所说,咱们只须要定义几个非凡时刻的动画状态即可。这个非凡时刻通常咱们叫做关键帧。
keyframes 关键帧
Keyframes 具备其本人的语法规定,他的命名是由 ”@keyframes” 结尾,前面紧接着是这个“动画的名称”加上一对花括号“{}”,括号中就是一些不同时间段款式规定,有点像咱们 CSS 的款式写法一样。
对于一个 ”@keyframes” 中的款式规定是由多个百分比形成的,如“0%”到 ”100%” 之间,咱们能够在这个规定中创立多个百分比,咱们别离给每一个百分比中给须要有动画成果的元素加上不同的属性,从而让元素达到一种在一直变动的成果,比如说挪动,扭转元素色彩,地位,大小,形态等。
不过有一点须要留神的是,咱们能够应用“fromt”“to”来代表一个动画是从哪开始,到哪完结,也就是说这个 “from” 就相当于 ”0%” 而 ”to” 相当于 ”100%”, 值得一说的是,其中 ”0%” 不能像别的属性取值一样把百分比符号省略,咱们在这里必须加上百分符号(“%”)如果没有加上的话,咱们这个 keyframes 是有效的,不起任何作用。因为 keyframes 的单位只承受百分比值。看一下具体的代码:
@keyframes IDENT {
from {Properties:Properties value;}
Percentage {Properties:Properties value;}
to {Properties:Properties value;}
}
/* 或者全副写成百分比的模式:*/
@keyframes IDENT {
0% {Properties:Properties value;}
Percentage {Properties:Properties value;}
100% {Properties:Properties value;}
}
其中 IDENT 是一个动画名称,你能够轻易取,当然语义化一点更好,Percentage 是百分比值,咱们能够增加许多个这样的百分比,Properties 为 CSS 的属性名,比如说 left,background 等,value 就是绝对应的属性的属性值。
2.3.2.2 JS 实现
利用 JavaScript 实现动画,能够采纳开源的 JavaScript 动画库或框架进行实现,例如:Anime.js 或者 TweenJS 上面咱们以 Anime.js 为例进行演示如何实现一个补间动画。
肯定水平上,anime.js 也是一个 CSS3 动画库,实用所有的 CSS 属性,并且实现的 @keyframes 能更不便的实现帧动画,代替 CSS3 简单的定义形式。应用对象数组的模式定义每一帧。
戳我:keyframes 实例
anime({
targets: 'div',
translateX: [{ value: 250, duration: 1000, delay: 500, elasticity: 0}, // 第一帧
{value: 0, duration: 1000, delay: 500, elasticity: 0} // 第二帧
]
}) // 这个例子实现了指标元素在两帧中实现程度位移
提供的 Timeline 能实现更为简单的动画成果,通过这个 Timeline,咱们能够保护不同的动画之间的关系,进而通过多个不同的动画组成一个更为简单的动画。
戳我:Timeline 实例
var myTimeline = anime.timeline();
// 通过.add()办法增加动画
myTimeline
.add({
targets: '.square',
translateX: 250
})
.add({
targets: '.circle',
translateX: 250
})
.add({
targets: '.triangle',
translateX: 250
});
2.3.3 SVG 动画
当咱们在实现动画的时候,缓缓会发现,大部分的元素都是图片,而且图片是提前预设好的,不能更改,只能用新的图片替换,例如当咱们要实现微笑动画的时候,须要画两张图,一幅是闭着嘴的,一幅是张嘴笑的,而后逐帧播放。这样的画面当你有足够多帧图片的时候,并不会看出僵硬,一旦低于 24 帧就是变得不天然了,那怎么在不减少工作量的前提下,实现晦涩的变动呢?咱们将关键帧动画的思维嫁接到元素本身扭曲变动上,就催生出了「柔性动画」的概念。
2.3.3.1 SVG 动画解说
从上图能够看出,元素之间是能够互相变动的,而且十分的晦涩,这样的动画并不需要 canvas 这种重武器,简略的 DOM 就能够实现,SVG 真的是一个神器,不仅在实现图标,字体上特点显明,在实现柔性动画方面也自成一家。
SVG 仍然是 DOM,他有本人独有的 Animation 标签,但也反对 CSS 的属性,其实现动画的 实质是依赖于线条和填充,线条的变动,导致填充区域的扭转,从而引起形态的变动。而线条则依赖于门路和锚点,门路和锚点的扭转,间接影响了线条的变动。
能够用 AI 等 SVG 编辑工具生成 SVG 图片后,配合 anime.js、GSAP 等现有库进行动画制作。
上面咱们通过 anime.js 来实现一个 SVG 门路动画.
SVG 绘制门路
戳我:SVG 实例
var path = anime.path('.motion-path-demo path');
anime({
targets: '.motion-path-demo .el',
translateX: path('x'),
translateY: path('y'),
rotate: path('angle'),
easing: 'linear',
duration: 2000,
loop: true
});
2.3.4 骨骼动画
SVG 实现的动画比拟部分和玲珑,应用范畴也比拟狭隘,然而当咱们实现简单的柔性动画,甚至游戏的时候,就还是须要用骨骼动画来实现。
从上图咱们能够看到龙的翅膀是一张图片,然而能够通过图片的部分的扭曲和变形,来实现鼓动翅膀时带来的肌肉膨胀和舒张。这样的动画是怎么实现的呢?这就要引出骨骼动画中,一个十分重要的概念:网格。
这里咱们比拟通俗的探讨下这个概念,要实现图片的部分变动,咱们就要把图片分块,分的每一块就称为网格,每个网格都有本人的顶点和边,顶点的位移会引起网格形态的变动,形态的变动就会带来所从属的图片的变动。网格的概念是不是很像门路和锚点,不论怎样的技术,在实现逻辑上都大同小异,重要的不是始终盯着不同和变动的局部,而是发现那些不变的中央,能力达到举一反三的成果。
制作这样的动画并不简单,你能够应用相似 Spine 和 DragonBones 这样的工具,然而做动画真的是一个体力活,你须要一直的调试,以求达到一种让人看起来难受的状态。
2.3.4.1 骨骼动画解说
骨骼动画就是把角色的各局部身材部件图片绑定到一根根相互作用连贯的“骨头”上,通过管制这些骨骼的地位、旋转方向和放大放大而生成的动画。
咱们常说的骨骼动画个别分为两个局部:
- 骨架(Skeleton)
- 蒙皮(Skin)
骨架波及的数据包含两个:
- 一是骨架的拓扑构造(连贯、父子关系)。
- 二是骨架的各种 pose,也就是每个动作对应的整个骨架的地位信息。
蒙皮则表白的是附丽在骨骼上的顶点的信息。
骨骼绑定的过程就是确定每个顶点受哪几根骨骼的影响,每根骨骼影响的权重有多大,譬如肘部的皮肤可能同时受大臂和小臂两根骨头的影响,而远离手肘的局部可能就只受小臂骨头影响。个别在 3D 骨骼动画里,每个顶点最多反对 4 - 8 根骨骼同时影响它就曾经能够很准确地表白整个蒙皮的成果了。
- 骨骼动画的劣势:
骨骼动画比传统的逐帧动画要求更高的处理器性能,但同时它也具备更多的劣势:
- 动画更加活泼真切。
- 图片资源占最小的存储空阔:骨骼动画的图片容量能够缩小 90%(配置文件 H5 的压缩计划前面详解)。
- 动画切换主动补间:过渡动画主动生成,让动作更加灵动。
- 骨骼可控:能够通过代码管制骨骼,轻松实现角色配备更换,甚至可对某骨骼做非凡管制或事件监听。
- 骨骼事件帧:动画执行到某个动作或某个帧,触发自定义事件行为。
- 动作数据继承:多角色可共用一套动画数据。
- 可联合物理引擎和碰撞检测。
2.3.4.2 骨骼动画制作
首先咱们来理解一下,骨骼动画是如何进行制作的:
制作骨骼动画次要是应用 Spine 和 DragonBones 这样的工具进行制作。
- DragonBones
DragonBones 是从 Flash 动画开始创作的,初衷是减小资源量,同时实现更为细粒度的动作(比方交互式的),让美术从繁琐的逐帧绘制 Sprie Sheet 的工作中解放出来,所以它把一个角色每一帧的 sprite sheet 拆分成一个个更小的根本图块,譬如胳膊,腿,躯干等等,而每个根本图块依然是最小的可管制单位。
以下游戏 & 渲染引擎都反对渲染 DragonBones 导出的文件:
- Spine
Spine 是一款针对游戏开发的 2D 骨骼动画编辑工具。Spine 旨在提供更高效和简洁 的工作流程,以创立游戏所需的动画。
业界免费业余 2D 骨骼动画编辑工具,动画设计师举荐易用稳固,以下游戏 & 渲染引擎都反对渲染 Spine 导出的文件:
上面咱们来制作一个骨骼动画小案例
- 创立骨骼
首先咱们须要创立手部的骨骼,如下图所示:
- 1 确保左上角为 SETUP 模式
- 确保选中左边视图中的根骨骼,创立骨骼时必须要选中父骨骼
- 单击左下角的 Create 按钮
- 开始顺次创立出 5 根骨骼
- 创立蒙皮网格
而后咱们须要给手部创立蒙皮网格(MESH),如下图所示:
首先,单击创立骨骼的 Create 按钮,退出骨骼创立模式
- 选中手部贴图(Attachment)
- 勾选其底部的 Mesh 选项
- 单击右下角的 Edit 按钮
- 呼出了 Edit Mesh 菜单
- 勾选 Edit Mesh 菜单中的 Deformed 选项
- 单击 Edit Mesh 菜单中的 Create 按钮
- 开始在手部创立网格顶点
- 能够单击 Edit Mesh 菜单中的 Modify 按钮对顶点进行位移
- 设置网格点权重
咱们须要给网格顶点设置各个骨骼的权重,整个过程如下图所示:
首先,敞开 Edit Mesh 菜单
- 确认勾选的还是手部的贴图
- 单击左下角的 Weights 按钮,呼出 Weights 菜单
- 单击 Weights 菜单底部的 Bind 按钮,来绑定骨骼
- 抉择手部的五根骨骼,直到它们都呈现 Weights 菜单里,留神不同的骨骼色彩是不一样的
- 单击 Weights 菜单的 Auto 按钮或者按
esc
键,来触发 Spine 的主动权重计算 - 勾选 Weights 菜单的 Overlay,咱们能够看到绑定后的权重热力求
- 动起来!
当初咱们要让手动起来了,咱们只展现一个蜿蜒手臂的动画即可。
首先,咱们须要设置关键帧,让咱们在第 1 帧和第 30 帧设置好关键帧,这两个关键帧对应的手臂地位是齐全一样的,因为咱们须要循环播放动画。
具体步骤如下图:
- 确保左上角的模式处于 ANIMATE 模式
- 选中手部的五根骨骼(按住
cmd
键或control
键顺次点选) - 选中第 0 帧
- 单击 Rotate 下的钥匙按钮,咱们对手臂的旋转属性设置关键帧
- 抉择第 30 帧
- 反复第 4 步的操作,使第 30 帧的关键帧与第 0 帧完全相同
接下来咱们只需微微旋转手臂,并在 0 -30 帧两头找一个帧当做关键帧即可:咱们抉择第 15 帧作为两头的关键帧。
- 抉择第 15 帧
- 确保 Rotate 按钮被选中
- 向上旋转 5 根骨骼到一个角度
- 按下 K 帧按钮进行关键帧设置
- 按下播放按钮来预览动画
额定的,我给另一只手、嘴巴、脸部和头发都做了 MESH,以下是动画的效果图:
2.3.4.3 前端展现骨骼动画
用 Spine 将制作好的骨骼动画进行导出输入资源(合图信息文件:atlas;动画信息文件:json,图片合图:png),将这些资源交由前端进行展现。
前端开发依据 Spine 或者 DragonBones 可能反对的渲染引擎,在我的项目中导入渲染引擎进行展现骨骼动画。
2.3.5 3D 动画
前端 3D 动画实现能够通过 perspective 属性操作用 CSS 3D 来实现,或者间接借助开源的 Three.js 开源库进行实现。
因为 3D 动画波及的内容较多,篇幅无限,前面咱们将专门开一章来解说前端 3D 动画。
三、现有计划总结
3.1 纯 CSS 实现
适宜场景: 简略的展现型动画
应用 transition\animation 属性,设置相应的关键帧状态,并且借助一些缓动函数来进行实现一些简单化的动画。
长处:开发成本低,不须要导入任何额定的依赖包
毛病与有余:只可能胜任做一些比拟简单化的动画,无奈实现一些过于负责的动画。
3.2 Anime.js
实用场景: 简略的展现型动画 + 弱交互型动画
Anime.js 是一个轻量级的 js 驱动的动画库,次要的性能有:
- 反对 keyframes,连贯多个动画
- 反对 Timeline,为实现更为简单的动画提供了可能
- 反对动画状态的管制 playback control,播放,暂停,重新启动,搜寻动画或工夫线。
- 反对动画状态的 callback,在动画开始,执行中,完结时提供回调函数
- 反对 SVG 动画
- 能够自定义贝塞尔曲线
- 任何蕴含数值的 DOM 属性都能够设置动画
- GitHub:
https://github.com/juliangarn… - codepen 仓库:
https://codepen.io/collection… - 文档演示:
http://animejs.com/documentat…
性能介绍:
肯定水平上,anime.js 也是一个 CSS3 动画库,实用所有的 CSS 属性,并且实现的 @keyframes 能更不便的实现帧动画,代替 CSS3 简单的定义形式。应用对象数组的模式定义每一帧。
戳我:keyframes 实例
anime({
targets: 'div',
translateX: [{ value: 250, duration: 1000, delay: 500, elasticity: 0}, // 第一帧
{value: 0, duration: 1000, delay: 500, elasticity: 0} // 第二帧
]
}) // 这个例子实现了指标元素在两帧中实现程度位移
提供的 Timeline 能实现更为简单的动画成果,通过这个 Timeline,咱们能够保护不同的动画之间的关系,进而通过多个不同的动画组成一个更为简单的动画。
戳我:Timeline 实例
var myTimeline = anime.timeline();
// 通过.add()办法增加动画
myTimeline
.add({
targets: '.square',
translateX: 250
})
.add({
targets: '.circle',
translateX: 250
})
.add({
targets: '.triangle',
translateX: 250
});
动画播放的管制,常见的有暂停,重播,持续,动画状态的跟踪,自动播放,循环次数,抖动成果
戳我:playback controls 实例
为动画提供了回调函数,在动画或工夫线实现的开始,期间或之时执行回调函数。
戳我:callback 实例
var myAnimation = anime({
targets: '#begin .el',
translateX: 250,
delay: 1000,
begin: function(anim) { // callback
console.log(anim.began); // true after 1000ms
}
});
反对 promise,动画完结后,调用 anime.finished 会返回一个 promise 对象。
戳我:promise 实例
反对 svg 绘制门路,目前不反对 canvas 绘制。
戳我:SVG 实例
对于 input 这样带有数值的元素标签,也能够通过 anime 实例来设置动画。
戳我:DOM ATTRIBUTES 实例
anime({
targets: input,
value: 1000, // Animate the input value to 1000
round: 1 // Remove decimals by rounding the value
});
长处:
- 不言而喻,anime.js 不仅实现了 CSS3 动画的深度封装,更多的是通过 js 驱动来实现操作动画的状态,timeline 实现了对于多个分支动画的治理,对于实现更为简单的动画提供了可能。
- 通过 anime.js 提供的 playback controls 和 callback,同时对于 promise 的反对,让咱们对于动画的简略交互有了操作的空间。
- 尽管不反对 canvas,然而反对 svg 绘制门路。
- 浏览器兼容性比拟好,Android 4 以上全副反对。
毛病:
Anime.js 做展现型动画是能够胜任的,然而对于特地简单的动画也是不太可能实现,在做交互性动画方面还是须要看场景,它更多适宜做一些小型的交互动画,相似于通过触摸屏幕踢足球这种强交互的,anime.js 就不是很有劣势了。
3.3 Lottie
实用场景: 简单的展现型动画
通过 AE 上的 Bodymovin 插件将 AE 中制作好的动画导出成一个 json 文件,通过 Lottie 对 JSON 进行解析,最初以 SVG/canvas/html 的形式渲染动画。
可能完整的展现设计师设计的各种各样简单的动画。
- 官网文档:
http://airbnb.io/lottie/ - codepen 仓库:
https://codepen.io/collection…
长处:
- 跨平台,一次绘制、一次转换、随处可用。
- 文件更小,获取 AE 导出的 JSON,最初通过 lottie 渲染为 canvas/svg/html 格局。
- 能够通过 api 操纵动画的一些属性,比方动画速度;增加动画各个状态的回调函数。
- 动画都是在 After Effects 中创立的,应用 Bodymovin 导出,并且本机渲染无需额定的工程工作。
- 解放前端工程师的生产力, 进步设计师做动效的自由度。
毛病:
- Bodymovin 插件待欠缺,依然有局部 AE 成果无奈胜利导出。
- 对于交互方面反对的还不是很好,更多的是用来展现动画。
- Lottie 对 json 文件的反对待欠缺,目前有局部能胜利导出成 json 文件的成果在挪动端上无奈很好的展示。
- 很多 AE 的成果是不反对的 查看反对的个性:Supported Features。
3.4 PixiJs
实用场景: 交互型动画,动画小游戏
PixiJS 是一个 2D 渲染引擎,Pixi 次要负责渲染画面。能够创立丰盛的交互式图形,动画和游戏,而无需深刻理解 WebGL API 或解决浏览器和设施兼容性的问题。与此同时,PixiJS 具备残缺的 WebGL 反对,如果须要,能够无缝地回退到 HTML5 的 canvas。PixiJs 默认应用 WebGL 渲染,也能够通过申明指定 canvas 渲染,WebGL 在挪动端 Android 4.4 browser 并不反对,不过能够应用 canvas 优雅降级。
- Github: https://github.com/pixijs/pix…
- 官网文档:http://pixijs.download/releas…
- 官方网站:http://www.pixijs.com/
- Examples:https://pixijs.io/examples/#/…
个性(摘自官网 DOCS):
- 反对 WebGL 渲染
- 反对 canvas 渲染(官网称 PixiJS 在 canvas 渲染方面当初是最快的)
- 非常简单易用的 API
- 丰盛的交互事件,比方残缺的鼠标和挪动端的触控事件
- Pixi 应用和 canvas Drawing 简直统一的 api,但不同于 canvas 的绘画 api,应用 Pixi 绘制的图形是通过 WebGL 在 GPU 上渲染
- 还有一系列个性须要在学习 PixiJs 之后理解
长处:
- 最大劣势莫过于通过 WebGL 来调用 GPU 渲染动画,这样极大的晋升了性能。
- 无需深刻理解 WebGL API 或者是浏览器兼容性(因为上面这条起因)。
- 反对 canvas 回退,以后设施不反对 WebGL 时,PixiJs 会应用 canvas 渲染动画。
- 残缺的 DOCS,比拟沉闷的社区,有利于深刻的学习。不过我感觉 PixiJs 学习老本相对来说还是很高的。
毛病:
- 首先是兼容的问题,WebGL 在 Android 4.4 是不反对的,只能应用 canvas 进行降级。
- Pixi 次要负责渲染画面,很多其它性能开发者得本人写或搭配其它库来应用,不过依照目前来看,是满足咱们的需要的。
性能:
对于手机版本 Android4.4 以上的手机,除了代码层面造成的性能有余,通过 WebGL 调用 GPU 渲染,性能还是有保障的。然而对于 Android4.4 只能应用 canvas 渲染,性能还是要看动画的复杂度,以及代码的优化
3.5 总结
简略的展现型动画:
对于比较简单的动画,咱们能够先尝试应用原生 CSS 的 transition\animation 属性来进行实现。
简略的展现型动画 + 弱交互:
对于简略的动画展现并且须要有简略的交互行为,比方用户点击一下暂停执行相应操作,待操作实现持续播放动画,交互方面比拟偏弱,能够采纳 Anime.js 的计划。
Anime.js 不仅仅反对所有的 CSS 属性,而且能够通过 Timeline,callback,playback controls 来管制动画执行的各个状态,并且 Anime.js 能够配合实现 SVG 动画。
简单的展现型动画:
- 如果所需的资源很小,能够先思考应用 GIF 动图或者逐帧动画 CSS 实现;
- 如果所需的资源较大,能够应用 Lottie 计划,而后设计同学用 AE 到处动画 json,将动画还原为 svg/canvas/html。
强交互 & 互动小游戏 & 骨骼动画:
- 对于交互场景比拟负责或者须要做一个小游戏,能够采纳 PixiJs,通过 WebGL 来渲染,利用硬件资源,极大的晋升性能,在兼容性方面,对于不反对 WebGL 的浏览器,能够应用 canvas 渲染来安稳回退;
- 如果是须要展现骨骼动画,能够通过 PixiJs 计划进行渲染由 Spine 或 DragonBones 输入的文件。