Laya引擎提供了哪些实现动画的方式?

在开始讲小游戏开发中会使用到的实现动画的方式,我们先来回顾一下在H5开发中如果你想做一个动画可以会用到实现动画的方式。

  • Gif:最简单的动画实现方式,不需要开发插手只需要设计师提供资源即可,仅仅适合重复播放不需要控制动画播放速度的动画;
  • CSS3 Keyframes:它是H5中最常使用的实现动画方式,通过控制每一帧的图片即可实现动作复杂的动画,在不考虑性能的前提下,这种动画实现方式适合大部分动画场景
  • CSS3 Transition:可以控制一个Dom元素的某些CSS属性实现过渡效果,这种动画实现方式一般是为了避免CSS属性改变时样式切换过于生硬而使用的;
  • 视频:目前已经有很多H5活动开始尝试直接通过视频作为动画的主要实现手段,通过JS响应用户的行为来播放不同的视频来实现和用户交互的效果,这种动画实现方式适合代码无法实现的超复杂动画
  • JS实现的动画:在上述实现动画的方式都无法实现时,只能通过JS大法来实现了,这里即包括2种情况:1、通过JS控制动画流程或控制Dom缓动;2、通过JS控制Canvas或WebGL来画动画,这种动画实现方式适合大部分复杂动画场景

回顾完H5中的一些动画实现方式,我们再来看看Laya游戏引擎给我们提供了哪些实现动画的方式。

  • 图集动画:这里的图集动画是游戏开发中的一个新概念,效果类似我们前面提到的CSS Keyframes动画,你可以简单的理解为图集 ≈ 雪碧图,二者的区别就是图集还多了一份每个图片对应位置关系的配置表;
  • 缓动动画:类似于前面提到的CSS Transition,这里说类似其实只是最终实现的效果类似,Laya提供的缓动动画是通过代码控制的,更像JQuery中的$(selector).animate() 或者 Tween.js的Tween.to()Tween.from(),提供Laya.Tween.from()Laya.Tween.to()函数控制元素从状态A逐步切换到状态B;
  • 时间轴动画:它可以说是Laya游戏开发中最常用的功能之一,初学者可以把它理解成多个缓动动画和图集动画的集合。在LayaIDE中还提供了时间轴动画编辑器,可以通过编辑时间轴上的每一个关键帧快速实现图片替换、位移、渐变、缩放等动画效果;
  • 动效模板:它是将基于时间轴动画的动画效果提炼出来抽象成一个效果模板,后续将效果附加给其他ui组件上,使得组件可以无需编码就实现已有的动画效果;
  • 骨骼动画:游戏中特有的一种模型动画效果,在模型中具有互相连接的骨骼组成的骨架结构,通过改变骨骼的朝向和位置从而形成动画,目前Laya支持2种骨骼动画,Spine骨骼动画DragonBone龙骨动画

目前,仅仅H5中的Gif动画无法在Laya游戏引擎中支持,其他动画方式都可以在Laya游戏中使用。下图为来自灵魂画师的动画对比图

我们应该怎么去使用这些动画?

介绍了游戏提供的实现动画的方式之后,我们来看一下该如何使用这些动画

1. 图集动画

图集动画本身就是直接播放图集资源,我们前面也提到了图集资源其实就是雪碧图搭配一个图片位置信息表,现在我们来看一下真实的图集资源是什么样子的。

下图为我们具体用到的图集资源,blink.atlas(每个图片资源的位置信息),blink.png(每一帧图片合成的雪碧图)

blink.atlas:记录每一张图片在雪碧图中的位置,内容如下:

{"frames":{"lz_01.png":{"frame":{"h":604,"idx":0,"w":650,"x":0,"y":0},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":15,"y":23}},"lz_03.png":{"frame":{"h":625,"idx":0,"w":667,"x":651,"y":0},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":42,"y":25}},"lz_05.png":{"frame":{"h":619,"idx":0,"w":623,"x":0,"y":605},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":63,"y":13}},"lz_07.png":{"frame":{"h":617,"idx":0,"w":670,"x":624,"y":626},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":20,"y":24}},"lz_09.png":{"frame":{"h":618,"idx":0,"w":688,"x":1295,"y":626},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":13,"y":30}},"lz_11.png":{"frame":{"h":617,"idx":0,"w":671,"x":0,"y":1244},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":35,"y":7}},"lz_13.png":{"frame":{"h":615,"idx":0,"w":676,"x":1319,"y":0},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":35,"y":13}},"lz_15.png":{"frame":{"h":642,"idx":0,"w":613,"x":672,"y":1244},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":71,"y":0}},"lz_17.png":{"frame":{"h":614,"idx":0,"w":702,"x":1286,"y":1245},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":10,"y":18}},"lz_19.png":{"frame":{"h":598,"idx":0,"w":614,"x":1984,"y":616},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":98,"y":24}},"lz_21.png":{"frame":{"h":613,"idx":0,"w":621,"x":1996,"y":0},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":79,"y":25}},"lz_23.png":{"frame":{"h":551,"idx":0,"w":602,"x":1989,"y":1215},"sourceSize":{"h":667,"w":720},"spriteSourceSize":{"x":53,"y":46}}},"meta":{"image":"blink.png","prefix":"lamp/blink/"}}

blink.png:所有帧对应的图片的合集(此处为原图,可自行下载作为demo使用),内容如下:

整体的使用过程也很简单,加载图集资源之后,直接播放即可

/**
 * 使用图集动画流程:
 * 1、创建动画实例
 * 2、加载图集资源 *.atlas
 * 3、添加到舞台
 * 4、播放动画
 */
 
// 创建动画实例
let animation = new Laya.Animation();
// 加载图集资源 blink.atlas,引擎会根据atlas文件自行查找到图片资源 blink.png
animation.loadAtlas('animation/blink.atlas', new Laya.Handler(this, () => {
    // 加载完成后,将动画添加到舞台上,并开始播放
    this.addChild(animation);
    // 无限循环播放
    animation.play()
}));

具体效果如下:

2. 缓动动画

缓动动画是提高游戏体验的重要手段,Laya引擎将缓动动画封装的很不错,对外只暴露出2个类,缓动类Laya.Tween、速度类Laya.Ease,通过这2个类即可快速实现缓动动画。我们来看一下如何实现一个方块移动且变色:

/**
 * 使用缓动动画流程:
 * 1、给需要移动的元素设置缓动后的样式属性即可
 */
 
// 舞台中添加元素,并设置大小和位置
let $box = new Laya.Box();
$box.size(100, 100).pos(0, 0);
$box.bgColor = 'red';
this.addChild($box)

// 通过缓动动画控制 $box位置移动、大小变化;整个动画耗时2秒
Laya.Tween.to($box, {
    width: 200,
    height: 200,
    x: 300,
    y: 700
}, 2000, Laya.Ease.linearInOut, Laya.Handler.create(this, () => {
    // 缓动动画结束后的操作
    Laya.Tween.to($box, {
        width: 100,
        height: 100,
        x: 0,
        y: 0
    }, 2000);
}));

具体效果如下:

3. 时间轴动画

Laya提供了2种方式实现时间轴动画,一是利用IDE的编辑模式创建时间轴动画,二是利用代码直接创建时间轴动画。我们来看一下如何实现一个方块移动且改变大小:

1、 通过编辑模式创建时间轴动画的步骤如下:

(a) 右击左侧场景目录,新建时间轴动画文件

(b) 将图片拖入场景,点击“动画编辑模式”,设置关键帧属性,修图片大小和xy属性

(c) 点击时间轴上对应的帧增加想要的属性,重复多次,添加多个关键帧

(d) 将生成的时间轴动画*.ani拖拽到场景中,重新编译即可看到效果

2、 通过代码创建时间轴动画的方式:

/**
 * 使用时间轴动画流程:
 * 1、给需要移动的元素设置每一帧的样式即可
 */

// 舞台中添加元素,并设置大小和位置
let $box = new Laya.Box();
$box.size(100, 100).pos(0, 0);
$box.bgColor = 'blue';
this.addChild($box)

// 创建时间轴动画
let timeline = new Laya.TimeLine();
timeline
    // 时间轴动画第一个序列
    .to($box, {
        width: 200,
        height: 200,
        x: 300,
        y: 700
    }, 2000)
    // 时间轴动画第二个序列
    .to($box, {
        width: 100,
        height: 100,
        x: 0,
        y: 0
    }, 2000);
timeline.play();

具体效果如下:

4. 动效模板

动效模板可以理解成是一个时间动画效果的抽象,类似于一个css3中定义一个@keyframes,只要给对应的dom添加上该keyframes即可执行相同的动画。目前动效模板只支持在IDE的编辑模式中创建。步骤如下:

(a) 右击左侧场景目录,创建动效模板

(b) 拖拽添加图片

(c) 通过鼠标控制组件的轴心点

(d) 编辑关键帧,添加摇动的动画效果,类似前面的编辑时间轴动画时的操作

(e) 在新的场景中新建图片组件,并将刚刚实现的动效模板 Shake.efc添加到图片组件中

具体效果如下:

5. 骨骼动画

骨骼动画的使用相对其他动画较为复杂,因为他需要先利用Laya自带的ui资源转换工具把现有的设计资源转换成Laya引擎认识的资源(纹理集*.png、龙骨资源信息*.sk)。因为目前市面上主流的做龙骨动画的工具有2种:DragonBone、Spine。其中Spine是收费软件,DragonBone是免费的,为了方便大家自己操作,我们就用DragonBones做演示工具。使用步骤:

(a) 下载DragonBones工具,官网地址

(b) 打开DragonBone工具后随便选择一个骨骼动画的示例,如果你有自己的龙骨动画资源也可以用自己的,这里为了方便就选了第一个资源。

(c) 导出laya引擎可以解析的资源,选择文件 -> 导出,选择正确的格式

(d) 利用IDE创建一个新的Laya2D项目,并把上述导出的文件放到项目的根目录下面

(e) 通过IDE提供的工具将龙骨动画资源转换引擎可用的资源

(f) 转换完成后,会在目录中生成*.png*.sk文件,将文件放到项目的资源文件中 laya/assets/dragonBone(dragonBone文件为自己创建,取别的名字也可以)。

(g) 在编辑模式下,按F9,增加勾选类库laya.ani.js

(h) 直接修改初始化项目中的src/script/GameUI.ts,修改为如下代码,重新编译即可看到效果

import { ui } from "./../ui/layaMaxUI";

export default class GameUI extends ui.test.TestSceneUI {
    onEnable(): void {
        /**
         * 使用龙骨动画的流程:
         * 1、创建动画模版
         * 2、加载龙骨资源
         * 3、通过模版创建龙骨动画实例
         * 4、播放龙骨动画
         */

        // 创建动画模版,方便后续存在复用动画的场景
        let templet = new Laya.Templet();
        // 加载龙骨资源
        templet.loadAni('dragonBone/Dragon_1.sk');
        // 处理加载完成事件
        templet.on(Laya.Event.COMPLETE, this, () => {
            // 通过模版创建动画实例
            // 0,使用模板缓冲的数据,模板缓冲的数据,不允许修改
            // 1,使用动画自己的缓冲区,每个动画都会有自己的缓冲区,相当耗费内存 (内存开销大,计算开销小,支持换装)
            // 2,使用动态方式,去实时去画 (内存开销小,计算开销大,支持换装,不建议使用)
            let skeleton = templet.buildArmature(1);
            skeleton.pos(200, 500);
            this.addChild(skeleton);
            // 播放动画
            skeleton.play(0, true);
        });
    }
}

具体效果如下:

常用的动画优化策略

基本上任何动画都可以通过时间轴动画或者图集动画来实现,只不过是实现的需要的图集大小的区别和是否适合的区别,我们快游戏本身对包体大小都有严格的控制,快游戏主包限制为10MB,如果按照设计师提供的动画资源直接使用,大概率会导致游戏包体很快就超过限制,针对这一问题这里列举几个常用的动画优化策略:

  • 压缩图集中每一个图片资源,裁剪图片的空白区域
  • 剔除图集动画中的重复图片
  • 调整动画的播放速率,跳帧删除动画图片
  • 尝试将复杂图集动画拆减为多个简单图集动画或者缓动动画,尽量减少纯粹的图集动画
  • 实现游戏角色的动作动画时,可以考虑使用骨骼动画

上述优化策略主要还是从如何减少动画资源大小方向上考虑。Laya引擎自身对动画做了很多自己的优化,保证了大家开箱即用即可,有兴趣了解Laya引擎,可以自行查看源码。

Laya2.x游戏引擎入门系列介绍

笔者19年5月开始深度参与了一个OPPO快游戏项目(类似微信小游戏),从零开始折腾到现在,终于算是入了H5游戏开发的门。目前关于Laya引擎开发快游戏的教程还不多,于是笔者决定把这几个月踩过的坑、解决的问题、总结的经验都记录下来,方便其他准备入坑的同学提前规避。

Laya2.x游戏引擎入门系列预计会写以下文章,记录如何从零开始完成一个快游戏的开发和上架:

同时,Laya2目前将引擎代码通过TypeScript进行了重构,大家如果在写代码中遇到什么疑问都可以直接在GitHub源码中找到答案,后续笔者也会写一些关于Laya2源码解析的文章,有兴趣的朋友可以关注。

第一次尝试写完整的教学文章,如有错误或不严谨的地方,请务必给予指正,十分感谢!

关于我

我是一个莫得感情的代码搬运工,每周会更新1至2篇前端相关的文章,有兴趣的老铁可以扫描下面的二维码关注或者直接微信搜索前端补习班关注。

精通前端很难,让我们来一起补补课吧!


sssh
41 声望7 粉丝