Flare动画进阶——创建可互动的一拳超人动画

栏目: 数据库 · 发布时间: 5年前

内容简介:这次和之前不一样,我们直接来看最终的动画实现效果:(使用琦玉老师作为例子,是因为他的画风比较简单,非常适合新手操作!!!)动画演示完毕,接下来,就是实现过程啦。

这次和之前不一样,我们直接来看最终的动画实现效果:

Flare动画进阶——创建可互动的一拳超人动画
Flare动画进阶——创建可互动的一拳超人动画

(使用琦玉老师作为例子,是因为他的画风比较简单,非常适合新手操作!!!)

动画演示完毕,接下来,就是实现过程啦。

听,是引擎的声音..

动画部分

如果你对于Flare的一些基础使用尚不熟悉,可以先去了解一下这篇文章: 打开Flutter动画的另一种姿势——Flare

绘制图形

首先,我们需要将一拳超人画出来,可以先在绘图软件上生成svg,再导入flare的项目中;或者也可以直接在flare项目中进行绘制。

这里为了方便起见,我是通过前者的方式去实现的

Flare动画进阶——创建可互动的一拳超人动画

将琦玉老师创造成功后,我就可以准备下一步操作了

【琦玉老师.svg】

添加约束

上面的动画里面,我们可以看到琦玉的脸部是随着手指移动的,所以我们需要将一起跟随移动的部位添加同一个约束

创建一个Node节点,将其display属性换成target

Flare动画进阶——创建可互动的一拳超人动画

然后我们开始将多个脸部内容与这个节点约束在一起,下面以左眼眶为例:

Flare动画进阶——创建可互动的一拳超人动画

其中我们有对每个约束的 Strength 进行调整,参数为1时,被约束的控件位置会和节点位置保持一致,所以这里会根据控件与节点的距离来设置不同的大小

Flare动画进阶——创建可互动的一拳超人动画

当我们所有约束都设置完成后,就可以看到如下效果:

Flare动画进阶——创建可互动的一拳超人动画

同时,我们这里将节点名字设置为了 ctrl_eyes

之后我们再创建三个非常简单的动画,动画名为idel、fail、success,其中,fail和success的效果如下:

Flare动画进阶——创建可互动的一拳超人动画
Flare动画进阶——创建可互动的一拳超人动画

接下来,我们开始准备用代码去控制这个动画!

代码部分

使用代码去控制动画才是这篇文章的重中之重,在此之前,先确保项目中已经添加了flare的依赖

flare_flutter: ^1.5.2
复制代码

上一篇文章中,我们只是使用了flare提供的最基本的功能,现在要真正实现动画与代码的交互,就不得不介绍一下 FlareController

FlareController

一般情况下,我们要通过继承的方式去使用 FlareController ,因为它是一个抽象类,这个类中有三个需要重写的方法:

  • initialize(FlutterActorArtboard artboard) :这个方法会在动画初始时调用,在整个FlareController的生命周期中,只会调用一次。其中的 artboard 参数表示画板对象,可以通过它获取到所有节点,以及所有的动画
  • setViewTransform(Mat2D viewTransform) : 这个方法用于进行矩阵坐标的传递,其中的 viewTransform 参数表示flare画板中的2d矩阵坐标
  • advance(FlutterActorArtboard artboard, double elapsed) :这个方法会在每一帧都调用一次,操作动画的主要逻辑就在这里。其中 elapsed 参数表示消耗的时间

官方给我们提供了一个 FlareControls 类,这个类封装好了一些基础的方法,所以我们实现的Controller继承这个类即可

接下来,我们来实现自定义的Controller,编写一个 MyController 继承 FlareControls

看一下其中的部分方法:

class MyController extends FlareControls{
    //用于获取ctrl_eyes节点
    ActorNode _eyeControl;
    
    // 存储"约束脸部节点"坐标
    Vec2D _eyeOrigin = Vec2D();
    Vec2D _eyeOriginLocal = Vec2D();
    ...
    
    @override
    void initialize(FlutterActorArtboard artboard) {
        super.initialize(artboard);
        _eyeControl = artboard.getNode("ctrl_eyes");
        if (_eyeControl != null) {
            _eyeControl.getWorldTranslation(_eyeOrigin);
            Vec2D.copy(_eyeOriginLocal, _eyeControl.translation);
        }
        play("idle");
    }
    ...
    
}
复制代码

initialize 中获取到了之前拖拽的脸部约束节点,并且进行了存储。

// 用于存储从flare转换到flutter的矩阵
  Mat2D _globalToFlareWorld = Mat2D();


  @override
  void setViewTransform(Mat2D viewTransform) {
    super.setViewTransform(viewTransform);
    Mat2D.invert(_globalToFlareWorld, viewTransform);
  }

复制代码

setViewTransform方法中进行了矩阵坐标的倒置。

其实关于矩阵坐标的相关逻辑都是比较晦涩抽象的,这里只要照搬即可,下面的 advance 方法同样如此

// 在flutter中当前焦点所在的坐标
  Vec2D _caretGlobal = Vec2D();

  // 在flare中当前焦点所在的坐标
  Vec2D _caretWorld = Vec2D();

  //判断是否正在输入
  bool _hasFocus = false;

  String _password = "";


  MyController({this.projectGaze = 100});
  
  //这个参数用于缩放从输入焦点到约束节点之间的距离
  final double projectGaze;
  
  @override
  bool advance(FlutterActorArtboard artboard, double elapsed) {
    super.advance(artboard, elapsed);
    Vec2D targetTranslation;

    if(_hasFocus){
      // 获取到flare中当前焦点所在的坐标
      Vec2D.transformMat2D(_caretWorld, _caretGlobal, _globalToFlareWorld);

      //这里是实现了动画的"呼吸"效果,是为了避免动画静止不动,让动画更加有趣
      _caretWorld[1] += sin(new DateTime.now().millisecondsSinceEpoch / 300.0) * 70.0;

      // 计算矢量方向
      Vec2D toCaret = Vec2D.subtract(Vec2D(), _caretWorld, _eyeOrigin);

      //获取比例,再进行缩放
      Vec2D.normalize(toCaret, toCaret);
      Vec2D.scale(toCaret, toCaret, projectGaze);

      //用于计算"约束节点"到输入焦点到距离
      Mat2D toFaceTransform = Mat2D();
      if (Mat2D.invert(toFaceTransform, _eyeControl.parent.worldTransform)) {
        Vec2D.transformMat2(toCaret, toCaret, toFaceTransform);
        targetTranslation = Vec2D.add(Vec2D(), toCaret, _eyeOriginLocal);
      }
    } else {
      targetTranslation = Vec2D.clone(_eyeOriginLocal);
    }

    Vec2D diff =
    Vec2D.subtract(Vec2D(), targetTranslation, _eyeControl.translation);
    Vec2D frameTranslation = Vec2D.add(Vec2D(), _eyeControl.translation,
        Vec2D.scale(diff, diff, min(1.0, elapsed * 5.0)));


    _eyeControl.translation = frameTranslation;

    return true;
  }
复制代码

advance方法返回 true 表示每帧都进行刷新

实现完MyController之后,再搭配官方提供的 tracking_text_input.dartinput_helper.dart 就可以实现 琦玉眼睛跟随输入框的效果了


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

精通Git(第2版)

精通Git(第2版)

Scott Chacon、Ben Straub / 门佳、刘梓懿 / 人民邮电出版社 / 2017-9 / 89.00元

Git 仅用了几年时间就一跃成为了几乎一统商业及开源领域的版本控制系统。本书全面介绍Git 进行版本管理的基础和进阶知识。全书共10 章,内容由浅入深,展现了普通程序员和项目经理如何有效利用Git提高工作效率,掌握分支概念,灵活地将Git 用于服务器和分布式工作流,如何将开发项目迁移到Git,以及如何高效利用GitHub。一起来看看 《精通Git(第2版)》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具