很早以前, 就想对芊云全景的语音讲解模块做个卡通人物做讲解, 第一次调研的时候, 是想使用 live2D, 也就是我博客主页这只小猫咪的实现方式, 但是这个做模型的方法特别 复杂, 而且没有现成的可用的客服类模型, 于是就搁置了, 但是近期发现某20 云居然上线了这个语音讲解功能, 并且命名: 元宇宙 xxx, 于是我又开始调研其他方案。
第一种方案, 就是去年调研过的 live2D 技术, 做模型太复杂了放弃了
第二种方案: 想使用建模的方式, 做一个 fbx 模型, 带动画那种, 然后设定几组动画重复播放即可, 但是去淘宝问了一圈, 淘宝店家报价 1w, 果断放弃
第三种方案: 既然 3D 的搞不成, 那弄 2D 的总可以了吧, 结果淘宝报价 3000 元, 放弃
作为一个动漫专业毕业的来说, 总不能东西就不做了吧~ 开始寻找能在网页上直接制作 2D 动画的网站, 看看能不能找到一些有用的
果然找到了2个网站可以做类似的2D 动画: 一个叫来画, 一个叫万彩动画大师
来画这个软件研究了下, 动画动作比较简单, VIP 相对便宜一些,
万彩动画这个, 动画场景比较多, 有我能使用的东西, 但是 VIP 一个月 900 快, 真实忍不了啊,
还是扒素材看看吧, 开始分析这个网站的动画生成方案, 看了看, 发现了一些端倪,
这个网站的动画, 都是用序列帧做的, 每个动画, 都有一个类似的配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "1": { "png": "595a95c6a3a9c6cf11c8bb74a92aee94.png", "json": "8bdadf1036cf4a33912d3200c9cc009c.json", "time": 5.16 }, "2": { "png": "55c831370bdd776bbf7b275e842f865a.png", "json": "b2bfa00187daa2741336a34d8bd96111.json", "time": 5.16 }, "3": { "png": "42d45f6958f4c583b3c4ef58bc731045.png", "json": "3f651a72df83b5bc9937e4713a3e75a1.json", "time": 5.16 }, .... |
其中,
png 就是动画的序列帧图片,
json 是配置文件
刚开始看到这个序列帧图片, 我以为直接拿图片去解析播放就可以了, 于是简单写了一段 css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@keyframes run { from { background-position-x: 0; } to{ background-position-x: -9196px; } } .play { background-image: url("r1.webp"); background-repeat: no-repeat; width: 23px; height: 62px; position: absolute; animation: run 12s steps(42); } |
但是发现不对, 这个动画播不起来了, 跳来跳去, 研究完发现他们的序列帧图的位置是不固定的, 我这种方式就用不了了,
然后开始分析了一下他们的 json 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "frames": [ { "filename": "25-129-1.png", "frame": {"x":6517,"y":1,"w":139,"h":406}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":141,"y":120,"w":139,"h":406}, "sourceSize": {"w":409,"h":614} }, ..... |
发现其中有 w 和 h 这两个参数, 猜测应该就是宽高了吧, 于是使用配置文件播放一次看看
随手引入一个 jq, 加载配置文件播放动画
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$.get('6500.json').then(res=>{ const frames = res.frames const dom = document.querySelector('.play'); let i = 0; setInterval(_=>{ i++; if (i >= frames.length){ i = 10; } dom.style.width = frames[i].frame.w + 'px'; dom.style.height = frames[i].frame.h + 'px'; dom.style.backgroundPositionX = -1 * frames[i].frame.x + 'px'; dom.style.backgroundPositionY = frames[i].frame.y + 'px'; }, 42) }) |
果然是这样, 动画播起来了, 还算流畅, 但是也有问题
播放期间这个人物会来回跳, 不是站这里不动, 而官方他们的是不动的, 于是继续分析 json 文件, 发现他们使用了定位, 于是我也加上定位,
并且发现 spriteSourceSize 这个参数里有个 x 和 y, 值和第一帧是一样的, 于是把这个也带进去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<script> $.get('6500.json').then(res=>{ const frames = res.frames const dom = document.querySelector('.play'); let i = 0; setInterval(_=>{ i++; if (i >= frames.length){ i = 10; } dom.style.width = frames[i].frame.w + 'px'; dom.style.height = frames[i].frame.h + 'px'; dom.style.backgroundPositionX = -1 * frames[i].frame.x + 'px'; dom.style.backgroundPositionY = frames[i].frame.y + 'px'; dom.style.left = frames[i].spriteSourceSize.x + 'px'; dom.style.top = frames[i].spriteSourceSize.y + 'px'; }, 42) }) </script> |
播放了一下, 果然没有问题了,
后面给逐帧动画的人物简单调整一下, 多拼接几组动作, 瞬间感觉省了不少钱!
贫穷使我快乐
逐帧原图: https://online.xiuzhan365.com/tjuu/Draft/kpxq/files/extfile/ffd9374822dfa728db105eeaa382af6a.png?x-oss-process=image/format,webp/quality,lossless
配置文件: https://online.xiuzhan365.com/tjuu/Draft/kpxq/files/extfile/a913543e87bc73ace983f5a17d81b1f9.json