使用雪碧图实现帧动画
孙泽辉

在网页上实现帧动画,你肯定想到了gif,但是项目大了性能不好,今天讲一种使用雪碧图实现的帧动画,实现方式巧妙,值得学习。

开新坑了,krpano一款强大的vr引擎,直接能跑在网页上!

雪碧图CSS Sprites 不知道是啥的请看:前端性能优化-雪碧图及其实现 - 简书 (jianshu.com)

图片是一张有全部帧的大图,每个帧都切割出来的,如何播放呢?只需要有一个视口,这个视口是一帧的宽高,然后调整图片位置,来实现每一帧的播放。

image

这就是一张雪碧图,这张图是一行一帧,一共6行也就是6帧的动画,这个很重要!

思路

既然想让图片位置动起来,并且不停的播放,首先想到的就是开定时器然后改变位置。

对于这种一行一帧(竖着排)的雪碧图,列永远是第0列,行(i)就要一次轮换,也就是i%6

写法大概是

1
2
3
4
5
6
7
8
9
10
11
12
const rate = 6; // 帧率6帧每秒
const total = 6; // 总帧数
const frameWidth = 89;
const frameHeight = 103;
let i,j = [0, 0]

setInterval(()=>{
img.x = j * frameWidth; // x = 0
// y = [0,1,2,3,4,5] * frameHeight
img.y = (i % total) * frameHeight;
i++;
}, 1000 / rate)

但是对于一行多帧,有很多行的那种雪碧图怎么做呢?

更巧妙的做法是,算出所有帧数量,计算一行帧的数量,定义i保证在所有帧数量以内,然后按照公式

横坐标 = 当前帧 % x轴帧数量

纵坐标 = 当前帧 / x轴帧数量

理解不了的话,可以转换成二维数组那样去理解,你会发现这就是遍历二维数组的方法。

ps:二维数组[纵坐标][横坐标]

这样,能保证无论怎么排列都能播放。

实现

下面看在krpano的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!-- 脚本 -->
<action name="do_crop_animation" scope="local" args="framewidth, frameheight, framerate">
<!-- 纵坐标一共1帧 -->
calc(local.xframes, (caller.imagewidth /framewidth) XOR 0);
<!-- 算上横坐标一共6帧 -->
calc(local.frames, xframes * ((caller.imageheight / frameheight) XOR 0));
<!-- 此处frame是所有帧下标 -->
def(local.frame, integer, 0);
<!-- 设置第一帧 -->
calc(caller.crop, '0|0|' + framewidth + '|' + frameheight);

<!-- 动画部分 -->
setinterval(calc('crop_anim_' + caller.name), calc(1.0 / framerate),
if(caller.loaded,
<!-- 从第二帧开始 -->
inc(frame);
if(frame GE frames, if(caller.onlastframe !== null, callwith(caller, onlastframe() ) ); set(frame,0); );
<!-- 对当前帧数量取余,得到当前帧的横坐标 -->
mod(xpos, frame, xframes);
<!-- 对当前帧向总数量做除法,得到当前帧的纵坐标 -->
div(ypos, frame, xframes);
Math.floor(ypos);
mul(xpos, framewidth);
mul(ypos, frameheight);
<!-- 最终位置(x, y, frameWidth, frameHeight) -->
calc(caller.crop, xpos + '|' + ypos + '|' + framewidth + '|' + frameheight);
,
<!-- 当热点移除时停止动画 -->
clearinterval(calc('crop_anim_' + caller.name));
);
);
</action>

<!-- 场景 -->
<scene name="scene_1" title="项目全景" onstart="trace(1)" havevrimage="true" lat="" lng="" heading="">
<!-- ... -->
<style name="hotspot_active"
onloaded="do_crop_animation(89,109, 6)"
ondown="move()"
url="%SWFPATH%/index/1/active.png" edge="bottom" oy="0"/>
<hotspot name="active"
title="cat"
style="hotspot_active"
atv="34.120" ath="18.393" scale="3"
visible="true" />
</scene>

最终实现效果:

image
 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep
This site is deployed on
Total words 89.4k